2014-03-04 59 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

這個人清楚地從別處複製了這個答案,因爲他根據參數名稱判斷他甚至不知道它的作用。 –

相關問題