C# subtracting one list from another or checking if one list is completly containt in another list

瘦欲@ 提交于 2021-02-20 02:24:20

问题


How to subtract one list from another?

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

Doing this results in r => "def" instead of r=> "abc", "abc", "def". I mean, the second list only contains "abc" one time. So I want to remove only one instance of "abc" of the first list.

Btw: Is there a way to check if one list is completely contained in another list? Meaning when list1 only contains "abc" one time and list2 contains "abc" two times, list2 is not contained in list1. Except doesn't work with multiple values.


回答1:


You can write your own extension method 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;
}

As per Alexei Levenkovs comment, a little improvement...

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:


Except does not work, because it treats its operands as sets.

One approach to solving this would be creating counts, subtracting them, and then re-creating the list:

// 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();

This algorithm is O(M+N)

Demo.




回答3:


The List's Remove method removes the first occurrence of the string in the list:

        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);
        }

As a result, l1 contains just "abc" and "def" in this example.




回答4:


I think you should write a custom code for this one, something like this :

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;
                    }
                }
            }
        }

You can do better, this is just an example ^^




回答5:


var r = l1.Distinct().Except(l2).ToList();


来源:https://stackoverflow.com/questions/39378524/c-sharp-subtracting-one-list-from-another-or-checking-if-one-list-is-completly-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!