2016-09-07 163 views
0

如何從另一個列表中減去一個列表?C#從另一個列表中減去一個列表或檢查一個列表是否完全包含在另一個列表中

List<string> l1 = new List<string> { "abc", "abc", "abc", "def" }; 
    List<string> l2 = new List<string> { "abc" }; 
    var r = l1.Except(l2).ToList(); 

這樣做的結果R => 「DEF」 代替R => 「ABC」, 「ABC」, 「DEF」。 我的意思是,第二個列表只包含「abc」一次。所以我想只刪除第一個列表中的「abc」的一個實例。

Btw:有沒有辦法檢查一個列表是否完全包含在另一個列表中? 當list1只包含「abc」一次,list2包含「abc」兩次,list2不包含在list1中時的含義。 Except不適用於多個值。

+0

如果第二個列表包含兩個「abc」實例,應該從第一個列表中刪除兩個實例嗎? – SergeyS

+0

是的,確切地說。雖然我不確定,但當有4x「abc」時會發生什麼情況。也許某種錯誤。 –

回答

5

您可以編寫自己的擴展方法MyExcept

public static IEnumerable<T> MyExcept<T>(this IEnumerable<T> orgList, IEnumerable<T> toRemove) 
{ 
    var list = orgList.ToList(); 
    foreach(var x in toRemove) 
    { 
     list.Remove(x); 
    } 
    return list; 
} 

Alexei Levenkov的評論,有點起色......

public static IEnumerable<T> MyExcept2<T>(this IEnumerable<T> orgList, IEnumerable<T> toRemove) 
{ 
    var list = orgList.OrderBy(x => x).ToList(); 
    foreach (var x in toRemove) 
    { 
     var inx = list.BinarySearch(x); 
     if (inx >= 0) list.RemoveAt(inx); 
    } 
    return list; 
} 
+2

注意:由於O(n * m)的複雜性,對於大型列表來說,這將非常慢,對於小型列表來說很好且易於閱讀。 –

+0

我做了一些基準測試,不得不說,對於相對較小的列表(10和10項),第一種方法是迄今爲止最快的。使用列表(200和30條目),第一種方法和dasblinkenlight的版本類似。當列表變大時,來自dasblinkenlight的變體是最快的。由於我只有少於10條(10條和10條),L.B的第一條建議對我來說是正確的。第二個改進版本在我的所有測試中都丟失了。 –

0

我想你應該這樣寫的這一個自定義代碼,東西:

private void SubstractList(ref List<string> l1, List<string> l2) 
     { 
      foreach (string s2 in l2) 
      { 
       for (int i = 0; i < l1.Count; i++) 
       { 
        if (l1[i] == s2) 
        { 
         l1.RemoveAt(i); 
         break; 
        } 
       } 
      } 
     } 

你可以做的更好,這只是一個例子^^

4

Except不起作用,因爲它將它的操作數視爲集合。

一種方法來解決這將是創造數,減去它們,然後重新創建列表:

// Make word counts for l1 and l2 
var c1 = l1.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count()); 
var c2 = l2.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count()); 
// Make a count of the difference between the two 
var diff = new Dictionary<string,int>(); 
foreach (var p in c1) { 
    int sub; 
    if (!c2.TryGetValue(p.Key, out sub)) { 
     sub = 0; 
    } 
    diff[p.Key] = p.Value - sub; 
} 
// Reconstruct the result from counts 
var res = diff.SelectMany(p => Enumerable.Repeat(p.Key, p.Value)).ToList(); 

該算法是O(M + N)

Demo.

+1

注意事項:如果訂單比最重要的一步需要使用別的字典 - 即迭代原始列表並仔細過濾出需要注意的項目。 –

2

列表中的Remove方法刪除列表中的字符串的第一次出現:

 List<string> l1 = new List<string> { "abc", "abc", "abc", "def" }; 
     List<string> l2 = new List<string> { "abc", "abc" }; 
     foreach (string sl2 in l2) 
     { 
      l1.Remove(sl2); 
     } 

其結果是,L1包含在這個例子中只是「abc」和「def」。

0
var r = l1.Distinct().Except(l2).ToList(); 
相關問題