我有以下情况
class Person { string Name; int Value; int Change; } Listlist1; List list2;
我需要将2个列表组合成一个新的List
,如果它是同一个人,组合记录将具有该名称,list2中的人的值,更改将是list2的值 - list1的值.如果没有重复,则更改为0
这可以通过使用Linq扩展方法Union轻松完成.例如:
var mergedList = list1.Union(list2).ToList();
这将返回一个List,其中合并了两个列表,并删除了双精度数.如果您没有像我的示例中那样在Union扩展方法中指定比较器,它将使用Person类中的默认Equals和GetHashCode方法.例如,如果您想通过比较其Name属性来比较人员,则必须覆盖这些方法以自行执行比较.检查以下代码示例以完成该操作.您必须将此代码添加到Person类.
////// Checks if the provided object is equal to the current Person /// /// Object to compare to the current Person ///True if equal, false if not public override bool Equals(object obj) { // Try to cast the object to compare to to be a Person var person = obj as Person; return Equals(person); } ////// Returns an identifier for this instance /// public override int GetHashCode() { return Name.GetHashCode(); } ////// Checks if the provided Person is equal to the current Person /// /// Person to compare to the current person ///True if equal, false if not public bool Equals(Person personToCompareTo) { // Check if person is being compared to a non person. In that case always return false. if (personToCompareTo == null) return false; // If the person to compare to does not have a Name assigned yet, we can't define if it's the same. Return false. if (string.IsNullOrEmpty(personToCompareTo.Name) return false; // Check if both person objects contain the same Name. In that case they're assumed equal. return Name.Equals(personToCompareTo.Name); }
如果您不想将Person类的默认Equals方法设置为始终使用Name来比较两个对象,您还可以编写一个使用IEqualityComparer接口的比较器类.然后,您可以将此比较器作为Linq扩展联合方法中的第二个参数.有关如何编写这种比较器方法的更多信息,请访问http://msdn.microsoft.com/en-us/library/system.collections.iequalitycomparer.aspx
我注意到这个问题在2年后没有被标记为已回答 - 我认为最接近的答案是理查兹,但它可以简化为此:
list1.Concat(list2) .ToLookup(p => p.Name) .Select(g => g.Aggregate((p1, p2) => new Person { Name = p1.Name, Value = p1.Value, Change = p2.Value - p1.Value }));
虽然在任何一组中都有重复名称的情况下这不会出错.
其他一些答案建议使用联合 - 这绝对不是要走的路,因为它只会让你得到一个独特的列表,而不进行组合.
为什么你不只是使用Concat
?
Concat是linq的一部分,比做一个更有效率 AddRange()
在你的情况下:
Listlist1 = ... List list2 = ... List total = list1.Concat(list2);
这是Linq
var mergedList = list1.Union(list2).ToList();
这是Normaly(AddRange)
var mergedList=new List(); mergeList.AddRange(list1); mergeList.AddRange(list2);
这是Normaly(Foreach)
var mergedList=new List(); foreach(var item in list1) { mergedList.Add(item); } foreach(var item in list2) { mergedList.Add(item); }
这是Normaly(Foreach-Dublice)
var mergedList=new List(); foreach(var item in list1) { mergedList.Add(item); } foreach(var item in list2) { if(!mergedList.Contains(item)) { mergedList.Add(item); } }
这样做有几件事,假设每个列表不包含重复项,Name是唯一标识符,并且两个列表都没有排序.
首先创建一个追加扩展方法来获取单个列表:
static class Ext { public static IEnumerableAppend(this IEnumerable source, IEnumerable second) { foreach (T t in source) { yield return t; } foreach (T t in second) { yield return t; } } }
因此可以得到一个列表:
var oneList = list1.Append(list2);
然后分组名称
var grouped = oneList.Group(p => p.Name);
然后可以使用帮助程序处理每个组以一次处理一个组
public Person MergePersonGroup(IGroupingpGroup) { var l = pGroup.ToList(); // Avoid multiple enumeration. var first = l.First(); var result = new Person { Name = first.Name, Value = first.Value }; if (l.Count() == 1) { return result; } else if (l.Count() == 2) { result.Change = first.Value - l.Last().Value; return result; } else { throw new ApplicationException("Too many " + result.Name); } }
哪个可以应用于以下各个元素grouped
:
var finalResult = grouped.Select(g => MergePersonGroup(g));
(警告:未经测试.)