根据属性将两个列表合并为一个列表

本文关键字:列表 合并 一个 两个 属性 | 更新日期: 2023-09-27 18:20:33

我想问一下,是否有一种优雅高效的方法可以将MyClass的两个列表合并为一个?

MyClass看起来像这样:

  • ID:int
  • 名称:string
  • 外部ID:int?

并且列表是从不同的源填充的,并且列表中的对象共享ID,所以看起来是这样的:

MyClass instance from List1
ID = someInt
Name = someString
ExtID = null

和List2 中的MyClass实例

ID = someInt (same as List1)
Name = someString (same as List1)
ExtID = someInt

我基本上需要的是将这两个列表结合起来,所以结果是一个包含以下内容的列表:

ID = someInt (from List1)
Name = someString (from List1)
ExtID = someInt (null if no corresponding item - based on ID - on List2)

我知道我可以简单地使用foreach循环来完成这项工作,但我很想知道是否有更优雅的、可能更受欢迎的(由于性能、可读性)方法?

根据属性将两个列表合并为一个列表

根据优先级有很多方法,例如Union+Lookup:

//this will create a key value pairs: id -> matching instances
var idMap = list1.Union(list2).ToLookup(myClass => myClass.ID);
//now just select for each ID the instance you want, ex. with some value
var mergedInstances = idMap.Select(row => 
      row.FirstOrDefault(myClass => myClass.ExtId.HasValue) ?? row.First());

上面的好处是,它可以处理任何数量的任何列表,即使它们包含许多重复的内容,然后你可以很容易地修改合并的条件

一个小的改进是提取一种合并实例的方法:

MyClass MergeInstances(IEnumerable<MyClass> instances){
     return instances.FirstOrDefault(myClass => myClass.ExtId.HasValue) 
          ?? instances.First(); //or whatever else you imagine
}

现在只需在上面的代码中使用它

 var mergedInstances = idMap.Select(MergeInstances);

清洁、灵活、简单、无附加条件。表演方面并不完美,但谁在乎呢。

编辑:由于性能是第一位的,更多的选项

  1. 进行如上所述的查找,但仅针对较小的列表。然后遍历较大的,并进行所需的更改O(m log m)+O(n)。m-较小的列表大小,n-较大的列表大小-应该是最快的。

  2. 按元素ID对两个列表进行排序。创建一个for循环,在这两个列表中进行迭代,保持对两个列表具有相同id的元素的当前索引。将索引移动到两个列表中找到的下一个最小id,如果其中一个只有,则仅将其移动到.O(n log n)+O(m log m)+O(n);

这就是您想要的吗

var joined = from Item1 in list1
         join Item2 in list2
         on Item1.Id equals Item2.Id // join on some property
         select new MyClass(Item1.Id, Item1.Name, Item1.ExtID??Item2.ExtID);

编辑:如果你正在寻找外部加入,

var query = from Item1 in list1
            join Item2 in list2 on Item1.Id equals Item2.Id into gj
            from sublist2 in gj.DefaultIfEmpty()
            select new MyClass(Item1.Id, Item1.Name, sublist2??string.empty);

可读性方面,使用foreach循环不是一个太坏的主意。。

我建议在该类的方法中创建foreach循环,所以每次需要做这样的事情时,都会使用之类的东西

instanceList1.MergeLists(instanceList2)

使用此方法,您可以在合并操作中控制所需的一切。