找到两个字符串列表之间的区别

时间:2014-08-29 08:55:53

标签: c# .net string linq lambda

我很确定这是重复的,但我已经尝试了一切,但我似乎仍然无法得到差异。我有两个字符串列表:listA和listB。我正在尝试查找listA中不在B中的项目。

实施例: 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);

3 个答案:

答案 0 :(得分:6)

使用LINQ的Except方法:

listA.Except(listB).ToList();

答案 1 :(得分:1)

listA.Except(listB).ToList();

应该给出正确答案,但

set.SymmetricExceptWith(listB);

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

答案 2 :(得分:1)

你发布的所有代码都应该可以正常运行,所以无论如何你都会写错误“这需要很长时间”然后我认为你有性能问题。

让我们做一个非常快速和肮脏的比较(你知道做一个好的性能测试是一个漫长的过程,自我推销:基准已经用this free tool完成)。假设:

  • 列表无序。
  • 我们的输入中可能存在重复项,但我们不希望在结果中出现重复项。
  • 第二个列表始终是第一个列表的子集(假设是因为您使用的是SymmetricExceptWith,如果没有,那么它的结果与Except相比非常不同)。如果这是一个错误,只需忽略SymmetricExceptWith的测试。

两个 20,000个随机项列表(测试重复100次,然后是平均值,发布模式)。

Method                  Time [ms]
Contains *1                  49.4
Contains *2                  49.0
Except                        5.9
SymmetricExceptWith *3        4.1
SymmetricExceptWith *4        2.5

注意:

1 与foreach循环 2 循环用于 3 Hashset创建测量
4 未测量Hashset创建。我将此作为参考,但如果您没有第一个列表作为Hashset,则不能忽略创建时间。

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

Method                        Time [ms]
Except                            244.4
SymmetricExceptWith               259.0

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

Method                        Time [ms]
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,四核)上运行。另请注意,如此大量的数据缓存大小不会对测试造成太大影响。

Method                        Time [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()实现作为您自己特定的高度优化例程的起点。)