通过第二个列表使用 linq 修改列表

本文关键字:列表 linq 修改 第二个 | 更新日期: 2023-09-27 18:34:25

>我有 2 个列表。第一个是包含一堆对象的主列表,每个对象都有时间戳(日期时间)、类型(整数)、值(双精度)和标志(整数)。第二个列表具有类型(int)和描述(字符串)。

我的问题是我需要第一个列表在每个时间戳上具有所有类型。在没有这样的对象匹配(时间戳,类型)的情况下,我需要插入一个新对象(时间戳,类型,空值和空标志)。

如何使用 Linq 执行此操作?

示例对象:

var date = DateTime.UtcNow;
var points = new List<Point> {
    new Point { ts_utc = date            , type = 300, value = 25     , flags = 0 },
    new Point { ts_utc = date            , type = 400, value = 250    , flags = 0 },
    new Point { ts_utc = date            , type = 500, value = 2500   , flags = 0 },
    new Point { ts_utc = date.AddDays(1) , type = 300, value = 26     , flags = 0 },
    //new Point { ts_utc = date.AddDays(1) , type = 400, value = 260, flags = 0 },
    new Point { ts_utc = date.AddDays(1) , type = 500, value = 2600   , flags = 0 },
    new Point { ts_utc = date.AddDays(2) , type = 300, value = 27     , flags = 0 },
    new Point { ts_utc = date.AddDays(2) , type = 400, value = 270    , flags = 0 },
    new Point { ts_utc = date.AddDays(2) , type = 500, value = 2700   , flags = 0 }
};
var desc = new List<Description> {
    new Description{ type = 300, description = "300" },
    new Description{ type = 400, description = "400" },
    new Description{ type = 500, description = "500" },
};
 var q = from p in points
         join d in desc on p.type equals d.type into joined
         from subd in joined.DefaultIfEmpty(...)
         ...

查询不完整。在上面的列表中,我评论了一个点作为该(时间戳,类型)组合缺失值的示例。在那个地方,我想插入一个默认对象,其中包含现有类型的时间戳,但插入缺少的类型。值和标志应为空。我想一个小组可能会派上用场?

通过第二个列表使用 linq 修改列表

如果我

理解正确,您希望基于第一个集合中不存在的时间戳和类型组合集具有一个时间戳条目,但不是第二个集合中的所有类型。

var missing = points.GroupBy(p => p.ts_utc)
                    .SelectMany(g => desc.Where(d => g.All(p => p.type != d.type))
                                          .Select(d => new 
                                                       { 
                                                           ts = g.Key, 
                                                           type = d.type 
                                                       }));

这将首先按时间戳对点进行分组,然后对于每个分组,它将从描述列表中筛选具有组中存在的类型的任何描述,仅保留具有此时间戳不存在类型的描述。 然后,它从组键和"缺失"类型中选择时间戳。 最后,SelectMany将使结果变平。

然后,可以循环访问结果并将条目添加到points集合中。

foreach(var m in missing)
    points.Add(new Point { ts_utc = m.ts, type = m.type });
如果我

错了,请纠正我,但您想为列表 1 "填补空白" - 这样它就包含每个现有日期的每个现有类型的条目?

如果是这样,我只会让所有不同的项目进行迭代并创建一个嵌套的 foreach 循环......

List<DateTime> allExistingDates = points.Select(o => o.ts_utc).Distinct().ToList();
List<int> allExistingTypes = points.Select(o => o.type).Concat(desc.Select(o => o.type)).Distinct().ToList();
foreach (DateTime d in allExistingDates)
    foreach (int t in allExistingTypes)
        if (points.Any(o => o.ts_utc == d && o.type == t) == false)
            points.Add(new Point { ts_utc = d, type = t});

我发现这可以修复我的列表,而无需求助于多个查询:

var w = from p in points
        group p by p.ts_utc into g
        from d in desc
        select points.Where(r => r.ts_utc == g.Key && r.type == d.type).DefaultIfEmpty(new Point
        {
            ts_utc = g.Key,
            type = d.type
        }).FirstOrDefault();

我认为没有比这更短的了。两个(此时)其他答案都帮助我得出了这个解决方案。它不会创建不必要的新点,是 1 个 linq 查询,我认为(使用 1 个 linq 查询)它的效率再高不过了。