根据属性将两个列表合并为一个列表
本文关键字:列表 合并 一个 两个 属性 | 更新日期: 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);
清洁、灵活、简单、无附加条件。表演方面并不完美,但谁在乎呢。
编辑:由于性能是第一位的,更多的选项
进行如上所述的查找,但仅针对较小的列表。然后遍历较大的,并进行所需的更改O(m log m)+O(n)。m-较小的列表大小,n-较大的列表大小-应该是最快的。
按元素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)
使用此方法,您可以在合并操作中控制所需的一切。