【问题标题】:LINQ get difference of two lists -> preserve duplicatesLINQ 获取两个列表的差异 -> 保留重复项
【发布时间】:2014-03-12 07:35:01
【问题描述】:

假设两个列表 A 和 B

Dim A as New List(Of String) ( {"011", "011", "012", "001"})
Dim B as New List(Of String) ( {"011", "012", "111"});

我想得到从 A 到 B 的差异,在这个例子中是:[ "011", "001" ]

列表 A 和 B 都可能包含重复条目。如果列表 A 包含重复元素 e 并且列表 B 具有相同的值 e 仅一次 // 少于 A 的次数,结果列表应包含 (times e in A) - (times e in B) e

例如:

["001", "001", "001", "002"] ~ ["001", "001", "003" ] -> ["001", "002"]

这个问题的解决方案在经典的编程方式中是微不足道的,但我想用 LINQ 有一个(更短的)解决方案,但到目前为止我找不到工作代码,因为Intersect, Except and Union 都删除了重复项我需要保留。

我很高兴看到一个简单的 LINQ 解决方案

【问题讨论】:

    标签: linq


    【解决方案1】:
    var tmp = b.ToList();
    var result = a.Where(s => !tmp.Remove(s)).ToList();
    

    【讨论】:

    • 你需要!tmp.Contains(s) || 吗?我认为没有它你可以逃脱。
    • 我喜欢这个,它保留了a 的顺序,就像Except 等一样。也许您可以通过将 tmp 制作成字典或其他东西来加快速度,但对于两行代码来说,这很好。
    • 正是我想要的!非常感谢!
    • @BorisB。解决方案不能使用 HashSet! ["a","a","a"]~["a","a"] -> ["a"] 但是使用 HashSet 你得到 ->["a","a"] 结果(这是错误的!)
    • @juq:是的,两个内容相同的字符串具有相同的标识,会将答案还原为列表。
    【解决方案2】:

    干净地使用ToLookup 的替代方案可能是值得的 - 特别是如果列表变大。

    这里是:

    Dim AL = A.ToLookup(Function (x) x)
    Dim BL = B.ToLookup(Function (x) x)
    
    Dim C = _
        AL _
            .SelectMany(Function (xs) xs.Skip(BL(xs.Key).Count())) _
            .ToList()
    

    或者,在 c# 中:

    var AL = A.ToLookup(x => x);
    var BL = B.ToLookup(x => x);
    
    var C =
        AL
            .SelectMany(xs => xs.Skip(BL[xs.Key].Count()))
            .ToList();
    

    【讨论】:

    • 这是一个很好的实现,但我的两个列表都包含 0 - 10(最大!)元素,通常是 2-4,所以我认为创建查找所产生的开销对于我想要的来说太多了实现!感谢您的想法,问候
    • @juq - 因为列表太小而导致开销?代码在先进的现代硬件上运行,对吧?只有当您的列表很大时,您才应该担心。您应该担心的是可维护性。然后你想拥有尽可能简单的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-30
    • 1970-01-01
    • 2011-03-28
    • 1970-01-01
    相关资源
    最近更新 更多