查找两个字符串列表之间的差异
本文关键字:之间 列表 字符串 两个 查找 | 更新日期: 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()
实现作为您自己的特定高度优化例程的起点)。