如何检查集合的内容(> 2)是一样的

时间:2012-02-09 12:18:59

标签: c# linq

我有一个清单。出于正当理由,我多次复制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())));

谢谢大家的回复。

3 个答案:

答案 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