找出两个字符串列表之间的差异

3
我很确定这是一个重复的问题,但我已经尝试了一切,似乎仍然无法找到差异。我有两个字符串列表:listA和listB。我正在尝试查找不在B中的listA项。
例如: listA: "1", "2", "4", "7" listB: "2", "4" 我想要的输出是:"1","7"
下面是我尝试过的for循环和lambda表达式,但是这些需要很长时间:
//these two approaches take too long for huge lists

    foreach (var item in listA)
            {
                if (!listB.Contains(item))
                    diff.Add(id);
            }

    diff = listA.Where(id => !listB.Contains(id)).ToList();

//these don't give me the right differences

    listA.Except(listB).ToList();

    var set = new HashSet<string>(listA);
    set.SymmetricExceptWith(listB);

1
你想如何处理同一列表中的重复项?(假设listA或listB包含1、1、1、2、4、7、4、3)? - Raphaël Althaus
var diff=listA.Except(listB).ToList(); - Tim.Tang
1
listA.Except(listB).ToList() 的工作正常。请发布能够重现问题的代码。 - Sriram Sakthivel
抱歉,各位,它确实有效。 - Prabhu
那么如果listA包含("a", "c", "b"),而listB包含("a", "b", "c"),它们被认为是不同的还是相同的呢? - mg30rg
显示剩余2条评论
3个回答

7
使用LINQ的Except方法:
listA.Except(listB).ToList();

1
您发布的所有代码应该都可以正常工作,所以错误肯定出在别的地方。不过,由于您写道“这些需要很长时间”,我认为您可能存在性能问题。
让我们来进行一个非常快速而简单的比较(您知道,做一次良好的性能测试是一个漫长的过程,自我推销:使用这个免费工具已经完成了基准测试)。 假设:
- 列表是无序的。 - 我们的输入中可能有重复项,但是我们不希望结果中出现重复项。 - 第二个列表始终是第一个列表的子集(假设,因为您正在使用SymmetricExceptWith,如果不是,则其结果与Except相比是非常不同的)。 如果这是一个错误,请忽略SymmetricExceptWith的测试。
两个包含 20,000个随机项目的列表(测试重复100次,然后平均值,在发布模式下)。
方法                      时间[ms]
Contains *1                  49.4
Contains *2                  49.0
Except                        5.9
SymmetricExceptWith *3        4.1
SymmetricExceptWith *4        2.5

注意:

1 使用foreach循环
2 使用for循环
3 创建Hashset的时间测量
4 创建Hashset未被测量。我包括了这个参考,但如果你没有第一个列表作为Hashset,你不能忽略创建时间。

我们看到Contains()方法非常慢,所以在更大的测试中可以放弃它(无论如何,我已经检查过,它的性能不会变得更好甚至可比较)。让我们看看100万项列表会发生什么。

方法                        时间[毫秒]
Except                            244.4
SymmetricExceptWith               259.0

让我们尝试使其并行(请注意,对于此测试,我使用了旧的Core 2 Duo 2 GHz):

方法                        时间[毫秒]
Except                            244.4
SymmetricExceptWith               259.0
Except (parallel partitions)      301.8
SymmetricExceptWith (p. p.)       382.6
Except (AsParallel)               274.4
并行性能较差,现在LINQ Except是最佳选择。让我们看看它在更好的CPU(Xeon 2.8 GHz, 四核)上的运行情况。同时请注意,对于如此大量的数据,缓存大小不会对测试产生太大影响。
方法 时间 [ms] Except 127.4 SymmetricExceptWith 149.2 Except (parallel partitions) 208.0 SymmetricExceptWith (p. p.) 170.0 Except (AsParallel) 80.2
总之:对于相对较小的列表,SymmetricExceptWith() 的表现更好;对于大型列表,Except() 总是更好。如果你的目标是现代多核CPU,那么并行实现将更好地扩展。在代码中:
var c = a.Except(b).ToList();
var c = a.AsParallel().Except(b.AsParallel()).ToList();

请注意,如果您不需要List<string>作为结果,而IEnumerable<string>足够,则性能将大大提高(并且与并行执行的差异将更大)。
当然,这两行代码并不是最优的,可以大幅度提高效率(如果真的很重要,则可以选择ParallelEnumerable.Except()实现作为自己特定高度优化例程的起点)。

1
listA.Except(listB).ToList();

应该给出正确的答案,但是。
set.SymmetricExceptWith(listB);

不应该。SymmetricExcept会给出listA中不在listB中的项目加上ListB中不在listA中的项目。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接