2011-02-25 76 views
2

我有兩個相同類型的列表。該類型沒有標識符或任何其他有保證的編程方式。C# - 如何獲得沒有標識符的兩個列表的補充

  • 列表A:{1,2,2,3,5,8,8,8}
  • 列表B:{1,3,5,8}

我想要的從項目A不在B.

  • 所需的結果:{2,2,8,8}

如果類型有標識,我可以用如下語句的弗洛翼...

var result = listA 
     .Where(a => listB.Where(b => b.Id == a.Id).Count() == 0) 
     .ToList(); 

到目前爲止,我可以做到這一點的唯一方法是使用一個循環,我添加的每個項目,它不會出現在原始列表的次數。

foreach (var val in listB.Select(b => b.val).Distinct()) 
{ 
    var countA = listA.Where(a => a.val == val).Count(); 
    var countB = listB.Where(b => b.val == val).Count(); 
    var item = listA.Where(a => a.val == val).FirstOrDefault(); 

    for (int i=0; i<countA-countB; i++) 
    result.Add(item); 
} 

有一個更清潔的方式來實現這一目標?

編輯: 這是列表中對象的簡化版本。它來自一個打到另一個系統的Web服務。

public class myObject 
{ 
    public DateTime SomeDate { get; set; } 
    public decimal SomeNumber; { get; set; } 
    public bool IsSomething { get; set; } 
    public string SomeString { get; set; } 
} 

數據我收到具有用於SomeDate/SomeString和SomeNumber和IsSomething相同的值重複的值。兩個對象可能具有相同的屬性,但我需要將它們視爲不同的對象。

+1

我們可以用LISP代替C#嗎? – Shaded 2011-02-25 20:54:18

+2

你說你沒辦法比較項目,然後在你的第二個例子中用'val'比較它們。請解釋。 – 2011-02-25 21:00:08

+0

@Shaded:把它扔出去,如果C#沒有解決方案,那麼至少你有什麼東西。 :) – Mayo 2011-02-25 21:00:17

回答

9

試試這個:

var listA = new List<Int32> {1, 2, 2, 3, 5, 8, 8, 8}; 
var listB = new List<Int32> {1, 3, 5, 8}; 
var listResult = new List<Int32>(listA); 

foreach(var itemB in listB) 
{ 
    listResult.Remove(itemB); 
} 
+0

測試結果返回:{2,2,8,8} – 2011-02-25 21:07:15

+0

我剛剛用'Remove'發佈了一個解決方案,你雖然做得很好,但還是擊敗了我。 +1 – Marlon 2011-02-25 21:07:46

+0

@K Ivanov:我已經用它解決了問題 - 謝謝! – Mayo 2011-02-25 21:30:47

0

您可以對兩個列表進行排序,然後同時對它們進行迭代。

public IEnumerable<int> GetComplement(IEnumerable<int> a, IEnumerable<int> b) 
{ 
    var listA = a.ToList(); 
    listA.Sort(); 
    var listB = b.ToList(); 
    listB.Sort(); 
    int i=0,j=0; 
    while(i < listA.Count && j < listB.Count) 
    { 
     if(listA[i] > listB[j]) {yield return listB[j];j++;} 
     else if (listA[i] < listB[j]) {yield return listA[i]; i++; } 
     else {i++;j++;} 
    } 
    while(i < listA.Count) 
    { 
     yield return listA[i]; 
     i++; 
    } 
    while(j < listB.Count) 
    { 
     yield return listB[j]; 
     j++; 
    } 
} 

我不知道這是否「更清潔」,但它應該是更大的數據集上的表現。

0

這兩個列表中的對象是否有相同的實例?如果是這樣你可以使用.Where(a => listB.Where(b => b == a).Count() == 0)

或者

.Where(a => !listB.Any(b => b == a)) 
+0

不幸的是我沒有辦法比較平等。它實際上是一個可以重複的字符串/整數的對象(儘管在現實生活中它們是獨特的對象)。 – Mayo 2011-02-25 20:57:30

+0

'=='運算符不檢查相等性,它比較引用。它會返回'true'來指向同一個實例的兩個引用。 – 2011-02-25 21:18:35

0

這是一個有點討厭,但你想要做什麼。不確定性能。

var a = new List<int> { 1, 2, 2, 3, 5, 8, 8, 8 }; 
var b = new List<int> { 1, 3, 5, 8 }; 

var c = from x in a.Distinct() 
     let a_count = a.Count(el => el == x) 
     let b_count = b.Count(el => el == x) 

     from val in Enumerable.Repeat (x, a_count - b_count) 
     select val; 
+1

我剛剛檢查了Enumerable.Except的實現:它不適用於重複項,所以這裏的結果是{2},而不是請求的{2,2,8,8} – 2011-02-25 21:00:24

+0

我編輯了答案,它現在返回'{2,2,8,8}'。 – 2011-02-25 21:15:24

1

我缺少什麼?

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<int> a = new List<int>(); 
     a.Add(1); 
     a.Add(2); 
     a.Add(2); 
     a.Add(3); 
     a.Add(5); 
     a.Add(8); 
     a.Add(8); 
     a.Add(8); 
     List<int> b = new List<int>(); 
     b.Add(1); 
     b.Add(3); 
     b.Add(5); 
     b.Add(8); 

     foreach (int x in b) 
      a.Remove(x); 

     foreach (int x in a) 
      Console.WriteLine(x); 

     Console.ReadKey(false); 
    } 
} 
+6

收集初始值設定項:-) – 2011-02-25 21:20:22

+0

:D但我的帖子看起來更大! – SQLMason 2011-02-25 21:25:27

0

你爲什麼不實現自己的相等比較器爲您myObject

public class YourTypeEqualityComparer : IEqualityComparer<myObject> 
{ 
    public bool Equals(myObject x, myObject y) 

    public int GetHashCode(myObject obj) 
} 

,然後用它是這樣的:

var list1 = new List<myObj>(); 
var list2 = new List<myObj>() 
list1.RemoveAll(i => 
    list2.Contains(list1), 
    new YourTypeEqualityComparer() 
); 

現在list1含有結果。