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

本文关键字:之间 列表 字符串 两个 查找 | 更新日期: 2023-09-27 18:20:01

我很确定这是重复的,但我已经尝试了所有的方法,但似乎仍然无法获得差异。我有两个字符串列表:listA和listB。我正在列表A中查找不在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);

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

使用LINQ的Except方法:

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

应该给出正确的答案,但是

set.SymmetricExceptWith(listB);

不应该。SymmetricExcept将为列表A中不在列表B中的项加上列表B中不在listA中的项

您发布的所有代码都应该可以正常工作,所以错误就在另一个地方。无论如何,如果您编写"这些代码需要很长时间",那么我想您会遇到性能问题。

让我们做一个非常快速和肮脏的比较(你知道做一个好的性能测试是一个漫长的过程,自我提升:基准测试已经用这个免费工具完成了)。假设:

  • 列表是无序的
  • 我们的输入中可能有重复项,但我们不希望结果中有重复项
  • 第二个列表始终是第一个列表的子集(假设是因为您使用的是SymmetricExceptWith,如果不是,则其结果与Except非常不同)。如果这是一个错误,就忽略SymmetricExceptWith的测试

20000个随机项目的两个列表(重复测试100次,然后取平均值,发布模式)。

方法时间[ms]包含*1 49.4包含*2 49.05.9除外对称例外与*3 4.1对称ExceptWith*4 2.5

注:

1foreach循环
2循环3测量的哈希集创建
4未测量哈希集创建。我包含了这个作为参考,但如果您没有第一个列表作为哈希集,您就不能忽略创建时间

我们看到Contains()方法非常慢,所以我们可以在更大的测试中放弃它(无论如何,我检查了一下,它的性能不会变得更好,甚至没有可比性)。让我们看看1000000个项目列表会发生什么。

方法时间[ms]244.4除外SymmetricExceptWith 259.0

让我们试着让它并行(请注意,在这个测试中,我使用的是旧的Core 2 Duo 2 GHz):

方法时间[ms]244.4除外SymmetricExceptWith 259.0除(平行分区)301.8对称例外(第页)382.6除(AsParallel)274.4

并行性能更差,LINQ Except是现在最好的选择。让我们看看它是如何在更好的CPU(Xeon 2.8 GHz,四核)上工作的。还要注意,数据缓存大小如此之大不会对测试产生太大影响。

方法时间[ms]127.4除外SymmetricExceptWith 149.2除(平行分区)208.0SymmetricExceptWith(第页)170.0除(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()实现作为您自己的特定高度优化例程的起点)。