2015-11-05 295 views
1

標題可能會產生誤導,這樣的例子:刪除「重複」

我有一個類:

class Pair 
{ 
    Book Book1; 
    Book Book2; 
} 

我有這些列表:

var list = new List<Pair>(); 

list.Add(new Pair() { 
    Book1 = new Book() { Id = 123 }, 
    Book2 = new Book() { Id = 456 } 
}); 

list.Add(new Pair() { 
    Book1 = new Book() { Id = 456 }, 
    Book2 = new Book() { Id = 123 } 
}); 

現在,儘管書被「翻轉」,我的系統應該將這些視爲重複。

我需要一個方法來從列表中刪除這些'duplicates'中的一個一個(任何一個 - 所以我們假設第一個使它簡單)。

我已經試過

 var tempList = new List<Pair>(); 
     tempList.AddRange(pairs); 

     foreach (var dup in pairs) 
     { 
      var toRemove = pairs.FirstOrDefault(o => o.Book1.Id == dup.Book2.Id 
                 && o.Book2.Id == dup.Book1.Id); 

      if (toRemove != null) 
       tempList.Remove(toRemove); 
     } 

     return tempList; 

這不返回任何項目(假設上面的例子),因爲這兩個Pair對象將滿足拉姆達的情況下,我只有一個,雖然刪除一個。

注意:如果我只是刪除從集合馬上(而不是從臨時列表)元素這不會發生 - 但後來我就不能來遍歷它沒有例外。

+0

'dup.Book.Id'?這不應該是Book1或Book2嗎? – Vlad274

+0

@ Vlad274 - 很好,我編輯了這個問題。 –

回答

4

您可以設置一個IEqualityComparer<Pair>具體類並傳遞到.Distinct()方法:

class PairComparer : IEqualityComparer<Pair> 
{ 
    public bool Equals(Pair x, Pair y) 
    { 
     return (x.Book1.Id == y.Book1.Id && x.Book2.Id == y.Book2.Id) 
      || (x.Book1.Id == y.Book2.Id && x.Book2.Id == y.Book1.Id); 
    } 

    public int GetHashCode(Pair obj) 
    { 
     return obj.Book1.Id.GetHashCode()^obj.Book2.Id.GetHashCode(); 
    } 
} 

,然後用它像這樣:

var distinctPairs = list.Distinct(new PairComparer()); 
+0

這是唯一正確的答案。 – ataravati

0

我已經設法找到解決方案,但這是我不滿意的一個。對於我想要做的工作來說,這似乎過於冗長。我現在做一個額外的檢查,以查看是否重複已經被添加到列表中:

if(toRemove != null && tempList.Any(o => o.Book1.Id == toRemove.Book2.Id 
             && o.Book2.Id == toRemove.Book1.Id)) 
              tempList.Remove(toRemove); 

我非常開放給其他建議。

+0

當做一個List.Remove你應該注意複雜性。 'Any'是O(N),'Remove'是O(N),foreach是O(N),所以你用O(N^3)的時間複雜度就是這樣。 –

+0

@GeorgePolevoy - 是的,你完全正確,這就是爲什麼我不滿意這種方法。這是爲了讓它工作(現在),但我不接受它。 –

2

的問題是,你都去掉重複。

試試這個:

var uniquePairs = list.ToLookup(p => Tuple.Create(Math.Min(p.Book1.Id, p.Book2.Id), Math.Max(p.Book1.Id, p.Book2.Id))).Select(g => g.First()).ToList(); 
1

我會用以下

foreach (var dup in pairs) 
    { 
     var toRemove = pairs.FirstOrDefault(o => o.Book1.Id == dup.Book2.Id 
                && o.Book2.Id == dup.Book1.Id 
                && o.Book1.Id > o.Book2.Id); 

     if (toRemove != null) 
      tempList.Remove(toRemove); 
    } 

確切地說,這將刪除重複那就是 「亂序」。但是,如果重複對具有相同順序的書籍,則此(和您的原件)將失敗。


更好的解決方案(因爲我們遍歷曾經配對反正)是使用一個HashSet

var hashSet = new HashSet<Tuple<int,int>>(); 
    foreach (var item in pairs) 
    { 
     var tuple = new Tuple<int,int>(); 
     if (item.Book1.Id < item.Book2.Id) 
     { 
      tuple.Item1 = item.Book1.Id; 
      tuple.Item2 = item.Book2.Id; 
     } 
     else 
     { 
      tuple.Item1 = item.Book2.Id; 
      tuple.Item2 = item.Book1.Id; 
     } 

     if (hashSet.Contains(tuple)) 
     { 
      tempList.Remove(dup); 
     } 
     else 
     { 
      hashSet.Add(tuple); 
     } 
    }