2014-03-04 56 views
93

我有一个类如下:检查两个列表相等

public class Tag { 
    public Int32 Id { get; set; } 
    public String Name { get; set; } 
} 

我有标签的两个表:

List<Tag> tags1; 
List<Tag> tags2; 

我用LINQ的选择让每个IDS标签列表。然后:

List<Int32> ids1 = new List<Int32> { 1, 2, 3, 4 }; 
List<Int32> ids2 = new List<Int32> { 1, 2, 3, 4 }; 
List<Int32> ids3 = new List<Int32> { 2, 1, 3, 4 }; 
List<Int32> ids4 = new List<Int32> { 1, 2, 3, 5 }; 
List<Int32> ids5 = new List<Int32> { 1, 1, 3, 4 }; 

IDS1应等于IDS2和ids3 ......都具有相同的编号。

IDS1不应该等于ids4和ids5 ...

我试过如下:

var a = ints1.Equals(ints2); 
var b = ints1.Equals(ints3); 

但两者给我假的。

什么是检查标签列表是否相等的最快方法?

UPDATE

我要寻找哪些职位标签是完全一样的一本书的标记。

IRepository repository = new Repository(new Context()); 

IList<Tags> tags = new List<Tag> { new Tag { Id = 1 }, new Tag { Id = 2 } }; 

Book book = new Book { Tags = new List<Tag> { new Tag { Id = 1 }, new Tag { Id = 2 } } }; 

var posts = repository 
    .Include<Post>(x => x.Tags) 
    .Where(x => new HashSet<Int32>(tags.Select(y => y.Id)).SetEquals(book.Tags.Select(y => y.Id))) 
    .ToList(); 

我使用Entity Framework,我得到的错误:

An exception of type 'System.NotSupportedException' occurred in mscorlib.dll but was not handled in user code

Additional information: LINQ to Entities does not recognize the method 'Boolean SetEquals(System.Collections.Generic.IEnumerable`1[System.Int32])' method, and this method cannot be translated into a store expression.

如何解决这个问题?

+0

你说的不是exacly平等是指,你的意思是所有的元素应该是不同的,或者只是它们不应该包含相同的元素,至少应该有一个不同的元素? –

+0

您的序列'ids5'包含重复项。那是故意的吗? – dasblinkenlight

+0

@ Selman22我的意思是这两个列表应该包含完全相同的元素......顺序没有关系 –

回答

152

使用SequenceEqual来检查序列相等,因为Equals方法检查引用相等

var a = ints1.SequenceEqual(ints2); 

或者,如果你不关心的元素顺序使用Enumerable.All方法:

var a = ints1.All(ints2.Contains); 

第二个版本还需要其他检查Count,因为它会返回true即使ints2包含比ints1多个元素。所以,更正确的版本是这样的:

var a = ints1.All(ints2.Contains) && ints1.Count == ints2.Count; 

为了检查不平等只是扭转All方法的结果:

var a = !ints1.All(ints5.Contains) 
+0

也许使用Except和Interect会是更好的选择吗?我不确定当你的解决方案集成到Linq to Entities查询中时是否快速,因为我需要多次选择所有的IDS ......或者我错了? –

+0

我不确定。您需要尝试两种方法,并查看生成的sql.BTW是否尝试了此解决方案?你有没有得到'NotSupportedException'或者它转换成功? –

+1

速度慢并且不处理重复项。 '[1,1,2]!= [1,2,2]' – CodesInChaos

89

List<T>相等并不会逐个检查它们。您可以使用LINQ's SequenceEqual method为:

var a = ints1.SequenceEqual(ints2); 

要忽略顺序,使用SetEquals

var a = new HashSet<int>(ints1).SetEquals(ints2); 

这应该工作,因为你在比较的ID,不包含重复的序列。如果是这样,并且需要考虑重复项,那么在线性时间内完成它的方法是编写一个基于散列的计数字典,为第一个序列的每个元素添加一个,为第二个元素的每个元素加上一个序列,并检查结果数都是零:

var counts = ints1 
    .GroupBy(v => v) 
    .ToDictionary(g => g.Key, g => g.Count()); 
var ok = true; 
foreach (var n in ints2) { 
    int c; 
    if (counts.TryGetValue(n, out c)) { 
     counts[n] = c-1; 
    } else { 
     ok = false; 
     break; 
    } 
} 
var res = ok && counts.Values.All(c => c == 0); 

最后,如果你是用O(N*LogN)解决方案很好,可以将两个序列进行排序,并使用SequenceEqual比较它们是否相等。

+1

使用SequenceEqual时,元素的顺序必须相同--OP需要_any_顺序中的相同元素。 –

+0

@DStanley你是对的,我最初错过了这个。现在应该没问题。 – dasblinkenlight

+0

编辑之前,你的答案是错误的,因为OP想忽略顺序,现在'SetEquals'不考虑重复项(OP不清楚)。 –

21
Enumerable.SequenceEqual(FirstList.OrderBy(fElement => fElement), 
         SecondList.OrderBy(sElement => sElement)) 
+8

你的lambda参数的名字很奇怪。他们不是名单,他们是一个元素。我要么在OP的上下文中使用'id',要么在通用上下文中使用'element'。 – CodesInChaos

+0

这个人清楚地从别处复制了这个答案,因为他根据参数名称判断他甚至不知道它的作用。 –

相关问题