Как удалить строки в списке из другого списка?

У меня есть 2 списка, имена которых listA и listB.

Я хочу удалить строки в listB, которые находятся в listA, но я хочу сделать это следующим образом:

если listA содержит: "bar", "bar", "bar", " foo" а listB содержит : "bar"

Он удаляет только 1 бар и результат будет: "бар", "бар", "фу"

код, который я написал, удаляет все "bar":

List<string> result = listA.Except(listB).ToList();

4 ответов


вы можете попытаться удалить его один за другим:

foreach (var word in listB)
    listA.Remove(word);

метод Remove удаляет только один элемент за раз и не создает исключение (но возвращает false), когда элемент не найден:https://msdn.microsoft.com/en-us/library/cd666k3e (v=против 110).aspx


var listA = new List<string>() { "bar", "bar", "bar", "foo" };
var listB = new List<string>() { "bar" };

foreach (var word in listB){
  listA.Remove(word);
}

вот более эффективный способ сделать это:

var countB = new Dictionary<string, int>(listB.Count);
foreach (var x in listB)
{
    int count;
    countB.TryGetValue(x, out count);
    countB[x] = count + 1;
}
listA.RemoveAll(x =>
{
    int count;
    if (!countB.TryGetValue(x, out count)) return false;
    if (count == 1)
        countB.Remove(x);
    else
        countB[x] = count - 1;
    return true;
});

это более быстрый метод, но он, вероятно, изменит порядок элементов первого списка. Шаги:

  • сопоставьте список с Dictionary<string, int> (назовем его listAMap), где key-элемент списка, а value-общее количество раз, когда значение произошло в listA;
  • итерация через listB и для каждого элемента listB, если этот элемент находится в listAMap, уменьшить их количество;
  • получить ключи listMapA используя ключи собственность словарей C# и повторите все ключи. Для каждого ключа, который имеет положительное значение, добавьте этот ключ в другой список в общей сложности его количество раз. Итак, если запись "bar" -> 2, затем дважды добавьте " bar " в новый список.

Общее время работы алгоритма -O (m + n), где m и n-количество элементов в обоих исходных списках. Это лучшее время работы, чем другие подходы, упомянутые здесь, которые имеют O (m * n) время выполнения. Очевидно, этот алгоритм использует больше пространства.


поддерживающий код для алгоритма выше:

//Step-1: Create the dictionary...
var listAMap = new Dictionary<string, int>();
foreach (var listAElement in listA)
{
    listAMap.ContainsKey(listAElement) ? listAMap[listAElement]++ : listAMap.Add(listAElement, 1);
}

// Step-2: Remove the listB elements from dictionary...
foreach (var listBElement in listB)
{
    if (listAMap.Contains(listBElement)) listAMap[listBElement]--;
}

//Step-3: Create the new list from pruned dictionary...
var prunedListA = new List<string>();
foreach (var key in listAMap.Keys)
{
    if (listAMap[key] <= 0) continue;
    for (var count = 0; count < listAMap[key]; count++)
    {
        prunedListA.Add(key);
    }
}

//prunedListA contains the desired elements now.