Дополнение двух списков? - PullRequest
6 голосов
/ 09 мая 2011

Допустим, у меня есть список строк:

A, B, C, D

Затем еще один список строк

B, C, D

Я хочу знать, какие элементы в первом списке отсутствуют во втором списке, поэтому результат будет A

Я не знаю, как называется метод расширения,,Я знаю, что могу использовать concat, union, intersect для аналогичных сравнений списков, но просто не знаю имени для выполнения этой конкретной задачи.

Приложение, меня интересуют дубликаты, поэтому, если первый список:

A, A, A, B, C, D

, а второй список

B, C, D

Я хочу получить

A, A, A

Спасибо!

Ответы [ 4 ]

15 голосов
/ 09 мая 2011

Вы можете использовать Кроме метода расширения , чтобы получить все элементы в списке, которых нет во втором списке:

var result = list1.Except(list2);
4 голосов
/ 09 мая 2011

Метод «Кроме» в BCL удаляет все дубликаты, а это не то, что вам нужно.

Если списки в задаче большие, то для эффективного выполнения этой задачи вы, вероятно, захотите тратить память в обмен на экономию времени. Что-то вроде:

// yield all members of "sequence" omitting those in "except"
static IEnumerable<string> Filter(
    this IEnumerable<string> sequence, 
    IEnumerable<string> except)
{
    var set = new HashSet<string>(except); // Burn memory to save time
    return from item in sequence 
           where !set.Contains(item) 
           select item;
}

Таким образом, вы получаете быстрый поиск каждый раз, когда тестируете предмет.

Позвони с

var sequence = new List<string>() { A, B, A, C, D };
var except = new List<string>() { B, C };
var result = sequence.Filter(except).ToList();
4 голосов
/ 09 мая 2011
var result = list1.Where(i => !list2.Contains(i));
0 голосов
/ 10 мая 2011

Если ваше определение дубликатов включает оба списка и , которые вы хотите эффективно вычислить, то вам нужно будет использовать другую структуру данных: пакет. Сумка - это набор, который позволяет дублировать.

Вот метод расширения, называемый BagDifference, который эффективно учитывает дубликаты в любом списке вместе с примером программы, вдохновленной ответом Эрика.

public class Bag<T> : Dictionary<T, int>
{
    public Bag(IEnumerable<T> sequence)
    {
        foreach (var item in sequence)
        {
            if (!ContainsKey(item)) this[item] = 0;
            ++this[item];
        }
    }
}

public static class EnumerableExtensions
{
    public static IEnumerable<T> BagDifference<T>(this IEnumerable<T> sequence1, IEnumerable<T> sequence2)
    {
        var bag1 = new Bag<T>(sequence1);
        var bag2 = new Bag<T>(sequence2);
        foreach (var item in bag1.Keys)
        {
            var count1 = bag1[item];
            var count2 = bag2.ContainsKey(item) ? bag2[item] : 0;
            var difference = Math.Max(0, count1 - count2);
            for (int i = 0; i < difference; i++)
                yield return item;
        }
    }
}

class Program
{

    static void Main(string[] args)
    {
        var sequence = new List<string>() { "A", "B", "A", "C", "D" };
        var except = new List<string>() { "A", "B", "C", "C" };
        var difference = sequence.BagDifference(except).ToList();
    }
}
...