当前位置:  开发笔记 > 编程语言 > 正文

使用linq从两个对象列表创建一个列表

如何解决《使用linq从两个对象列表创建一个列表》经验,为你挑选了5个好方法。

我有以下情况

class Person
{
    string Name;
    int Value;
    int Change;
}

List list1;
List list2;

我需要将2个列表组合成一个新的List ,如果它是同一个人,组合记录将具有该名称,list2中的人的值,更改将是list2的值 - list1的值.如果没有重复,则更改为0



1> Koen Zomers..:

这可以通过使用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


我不知道这是如何回答关于价值合并的问题.
供参考:还有`Concat`没有合并重复
@ J4N你可能会把'Union`与'Intersect`混淆起来吗?
您是否介意编辑此答案以便实际回答问题?尽管事实上它没有回答这个问题,但是因为它回答了标题和基本的谷歌查询("linq合并列表"),我觉得答案是如此高度投票是荒谬的.

2> Mike Goatly..:

我注意到这个问题在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 
    }));

虽然在任何一组中都有重复名称的情况下这不会出错.

其他一些答案建议使用联合 - 这绝对不是要走的路,因为它只会让你得到一个独特的列表,而不进行组合.


这篇文章实际上回答了这个问题,并且做得很好.
这应该是公认的答案.从来没有见过如此多的upvotes的问题,答案没有回答问题!

3> J4N..:

为什么你不只是使用Concat

Concat是linq的一部分,比做一个更有效率 AddRange()

在你的情况下:

List list1 = ...
List list2 = ...
List total = list1.Concat(list2);


你怎么知道它更有效率?
http://stackoverflow.com/questions/100196/net-listt-concat-vs-addrange - > Greg的评论:`实际上,由于延迟执行,使用Concat可能会更快,因为它避免了对象分配 - Concat没有'复制任何东西,它只是创建列表之间的链接,所以当枚举和你到达一个结束时它透明地带你到下一个开始!"这是我的观点.
这没有帮助的真正原因是它实际上并没有合并两个列表中存在的任何对象.
并且优点还在于,如果使用实体框架,则可以在SQL端而不是C#端完成.

4> 小智..:

这是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);
   }
}



5> Richard..:

这样做有几件事,假设每个列表不包含重复项,Name是唯一标识符,并且两个列表都没有排序.

首先创建一个追加扩展方法来获取单个列表:

static class Ext {
  public static IEnumerable Append(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(IGrouping pGroup) {
  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));

(警告:未经测试.)


你的'Append`几乎完全与开箱即用的`Concat`重复.
推荐阅读
135369一生真爱_890
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有