我有一个清单。出于正当理由,我多次复制List并将其用于不同目的。在某些时候,我需要检查所有这些集合的内容是否相同。
嗯,我知道怎么做。但作为“短手”编码(linq ...)的粉丝,我想知道我是否能用最短的代码行检查这个效率。
List<string> original, duplicate1, duplicate2, duplicate3, duplicate4
= new List<string();
//...some code.....
bool isequal = duplicate4.sequenceequal(duplicate3)
&& duplicate3.sequenceequal(duplicate2)
&& duplicate2.sequenceequal(duplicate1)
&& duplicate1.sequenceequal(original);//can we do it better than this
更新
Codeinchaos指出了我没有想到的某些情况(重复和列表顺序)。虽然sequenceequal会处理重复,但列表的顺序可能是个问题。所以我改变代码如下。我需要复制列表。
List<List<string>> copy = new List<List<int>> { duplicate1, duplicate2,
duplicate3, duplicate4 };
bool iseqaul = (original.All(x => (copy.All(y => y.Remove(x))))
&& copy.All(n => n.Count == 0));
UPDATE2
感谢Eric使用HashSet可以非常有效,如下所示。这不会覆盖重复。
List<HashSet<string>> copy2 =new List<HashSet<string>>{new HashSet<string>(duplicate1),
new HashSet<string>(duplicate2),
new HashSet<string> duplicate3),
new HashSet<string>(duplicate4)};
HashSet<string> origninalhashset = new HashSet<string>(original);
bool eq = copy2.All(x => origninalhashset.SetEquals(x));
UPDATE3 感谢Eric - 这篇文章中的原始代码与SequenceEqual一起使用排序。由于Sequenceequal将考虑集合的顺序,因此需要在调用sequenceequal之前对集合进行排序。我想这并不是一个很大的问题,因为排序非常快(nlogn)。
UPDATE4 根据Brian的建议,我可以使用查找。
var originallkup = original.ToLookup(i => i);
var lookuplist = new List<ILookup<int, int>>
{ duplicate4.ToLookup(i=> i),
duplicate3.ToLookup(i=> i),
duplicate2.ToLookup(i=> i),
duplicate1.ToLookup(i=> i)
};
bool isequal = (lookuplist.Sum(x => x.Count) == (originallkup.Count * 4)) &&
(originallkup.All(x => lookuplist.All(i => i[x.Key].Count() == x.Count())));
谢谢大家的回复。
答案 0 :(得分:7)
我有一个清单。我多次复制List并将其用于不同的目的。在某些时候,我需要检查所有这些集合的内容是否相同。
评论者然后问:
订单重要吗?或者只是内容?
你回答:
只有内容很重要
在这种情况下您首先使用了错误的数据结构。使用HashSet<T>
而不是List<T>
来表示无序项目集合,这些项目必须以便宜的方式进行比较,以便设置相等。
一旦你拥有散列集而不是列表中的所有东西,你可以简单地使用他们的SetEquals
方法来查看任何一对集合是否不相等。
或者:将所有内容保留在列表中,直到您要比较相等的位置。从其中一个列表初始化哈希集,然后使用SetEquals将该哈希集与其他列表进行比较。
答案 1 :(得分:4)
老实说,我想不出一个更有效的解决方案,但至于减少代码行数,请给它一个bash:
var allLists = new List<List<string>>() { original, duplicate1, duplicate2, duplicate3, duplicate4 };
bool allEqual = allLists.All(l => l.SequenceEqual(original));
或者,使用Any
运算符 - 在性能方面可能更好。
bool allEqual = !allLists.Any(l => !l.SequenceEqual(original));
编辑:确认后,Any
会在确定值后停止枚举来源。谢谢MSDN。
编辑#2:我一直在研究SequenceEquals
的效果。 This guy有一个很好的帖子,比较SequenceEquals
和更强制性的功能。我修改了他的例子以使用List<string>
,我的发现与他的相符。看来,就性能而言,SequenceEquals
在首选方法列表中并不高。
答案 2 :(得分:0)
您可以使用反射来创建通用比较器,并始终使用它。看看这个帖子,有一堆可以帮助你的代码:Comparing two collections for equality irrespective of the order of items in them