【问题标题】:Trying to get distinct values from two List<int> objects试图从两个 List<int> 对象中获取不同的值
【发布时间】:2011-02-03 10:06:24
【问题描述】:

我有 2 个列表对象:

List<int> lst1 = new List<int>();
List<int> lst2 = new List<int>();

假设它们有值:

lst1.Add(1);
lst1.Add(2);
lst1.Add(3);
lst1.Add(4);

lst2.Add(1);
lst2.Add(4);

我需要得到一个包含这两者的“不同”列表的对象;所以在这种情况下,返回将是 List {2, 3}。

有没有简单的方法来做到这一点?还是我需要遍历列表的每个值并进行比较?

我愿意使用 ObjectQuery、LINQ 等,因为这些列表来自数据库,并且可能有几百到几千个条目。

谢谢!

【问题讨论】:

  • 您的列表是否已排序,或者在此示例中这只是巧合?
  • 修改Sql不是更好吗?为什么要把不需要的东西穿过电线?
  • 你的目标不明确。在您的示例中,lst2 是 lst1 的完美重叠。那是保证吗?假设 lst2 还包含 5,那么期望的返回值是:{2,3} 还是 {2,3,5}?

标签: .net .net-3.5


【解决方案1】:

如果结果来自数据库,最好在那里处理它们。与内存操作相比,它会快得多,尤其是在结果很多的情况下。

如果您必须在代码中处理它们,您可以使用i4o - Indexed LINQ 来加快速度。

【讨论】:

    【解决方案2】:

    编辑:感谢 cmets,除了使用 Except 来获得对称差异之外,您还需要做一些额外的工作。如果将附加值添加到第二个列表,则单独除外是不正确的。要获得正确的结果,请尝试以下操作:

    var list1 = new List<int>(Enumerable.Range(1,4));
    var list2 = new List<int> { 1, 4, 6 };
    
    var result = list1.Except(list2).Union(list2.Except(list1));
    

    以上返回{2, 3, 6}

    请注意,如果您确实需要List&lt;int&gt;,则需要添加ToList(),否则上述操作将返回IEnumerable&lt;int&gt;


    使用Enumerable.Except method,产生两个序列的集合差:

    var result = lst1.Except(lst2);
    

    【讨论】:

    • 它适用于这个例子,但Except 给出了集合差异,而不是对称差异。特别是,lst2.Except(lst1) 会给出不同的答案(空列表)。
    • 在这种情况下,实际答案将是lst1.Except(lst2)lst2.Except(lst1) 的联合...
    • 同意@Thomas,这完全不是 OP 想要的。他想知道集合中哪些项目是不同的。
    • @Thomas @Dan @casperOne 感谢您的反馈。我已经更新了我认为现在应该产生正确结果的内容。
    • @casper:说这完全不是 OP 要求的,这当然不是真的。事实上,对于示例这会产生所需的输出。但是,@Thomas 是正确的,因为它是不对称的,所以 @Jon 的答案更正确。
    【解决方案3】:

    在 Linq 中:

    var distinct = lst2.Contact(lst1).Distinct().ToList();
    

    (您的解释似乎是说您想要两个列表中的唯一元素。但您的示例似乎是您想要两个列表中的 union)。

    【讨论】:

    • 这根本没有解决问题。他没有要求每个列表中的不同元素,也没有要求联合。他想要交叉路口的对面,即Except
    • 他说'我需要一个包含这两者的“不同”列表的对象'。我的解释是两个列表中的所有元素。然而他的例子与此相矛盾。
    • 我会依赖 OP 在描述中表达他的愿望,而不是正确使用术语。
    【解决方案4】:

    我相信,Ahmad 的 Except 几乎是正确的 - 但这不会为您提供 lst2 中但不在 lst1 中的项目。因此,在您给出的示例中,如果您将 5 添加到 lst2,我想您希望结果为 {2, 3, 5}。在这种情况下,您需要一个对称的差异。我不认为有任何方法可以在一次调用中直接在 LINQ to Objects 中执行此操作,但您仍然可以实现它。这是一种简单但低效的方法:

    lst1.Union(lst2).Except(lst1.Intersect(lst2)).ToList();
    

    (显然,如果您真的需要List&lt;T&gt; 而不是IEnumerable&lt;T&gt;,则只需要ToList()。)

    阅读方式是“我想要在任一列表中但不在两个列表中的项目。”

    使用Concat 可能会更有效——它仍然可以工作,因为Except 是一个基于集合的运算符,只会返回不同的结果:

    lst1.Concat(lst2).Except(lst1.Intersect(lst2)).ToList();
    

    【讨论】:

    • @Jon 你会说你的方法比我的快吗?我做了一个快速的迷你基准测试,看起来就是这样,尽管在更大的计划中可能可以忽略不计。我猜Concat 比使用Union 更有帮助。
    • @Ahmad:嗯,使用 Concat 我只做两个集合操作而不是三个......我认为分析它需要相当多的工作。我认为我的答案更容易理解——虽然我想我会......
    • 这对我来说已经足够了。有意义的是,设置操作的数量可能对其有所贡献,因为需要做更多的工作来确定哪些值与每个相应的操作匹配。谢谢!
    【解决方案5】:

    LINQ 将是一种简单的方法,根据其值对每个项目进行分组,然后仅选择具有一个元素的项目:

    from i in lst1.Concat(lst2)
    group i by i into g
    where !g.Skip(1).Any()
    select g.Key;
    

    在此处使用 Skip 可以确保不超过一个元素存在;如果序列中有 1 个或更少的元素,则返回一个空序列,在该序列上 Any 将返回 false。

    【讨论】:

      【解决方案6】:

      就是这样-

      var distinct = a.Union(b);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-09
        • 1970-01-01
        • 2013-11-02
        • 1970-01-01
        相关资源
        最近更新 更多