Добавить элементы в коллекцию, если коллекция НЕ содержит ее, сравнивая свойство элементов? - PullRequest
35 голосов
/ 13 июня 2011

По сути, как мне сделать так, чтобы я мог сделать что-то похожее на: CurrentCollection.Contains(...), кроме как путем сравнения, если свойство элемента уже находится в коллекции?

public class Foo
{
    public Int32 bar;
}


ICollection<Foo> CurrentCollection;
ICollection<Foo> DownloadedItems;

//LINQ: Add any downloaded items where the bar Foo.bar is not already in the collection?

Ответы [ 8 ]

48 голосов
/ 13 июня 2011

Вы начинаете с поиска элементов, которых еще нет в коллекции:

var newItems = DownloadedItems.Where(x => !CurrentCollection.Any(y => x.bar == y.bar));

И затем просто добавляете их:

foreach(var item in newItems)
{
    CurrentCollection.Add(item);
}

Обратите внимание, что первая операция может иметь квадратичную сложность, еслиразмер DownloadedItems близок к размеру CurrentCollection.Если это в конечном итоге вызывает проблемы (сначала измерьте!), Вы можете использовать HashSet, чтобы уменьшить сложность до линейной:

// collect all existing values of the property bar
var existingValues = new HashSet<Foo>(from x in CurrentCollection select x.bar);
// pick items that have a property bar that doesn't exist yet
var newItems = DownloadedItems.Where(x => !existingValues.Contains(x.bar));
// Add them
foreach(var item in newItems)
{
    CurrentCollection.Add(item);
}
11 голосов
/ 23 декабря 2011

Используя метод Р.Мартиньо Фернандеса и преобразовав в 1 строку:

CurrentCollection.AddRange(DownloadedItems.Where(x => !CurrentCollection.Any(y => y.bar== x.bar)));
9 голосов
/ 12 января 2018

Вы можете использовать Enumerable.Except :

Он будет сравнивать два списка и возвращать элементы, которые появляются только в первом списке.

CurrentCollection.AddRange(DownloadedItems.Except(CurrentCollection));
4 голосов
/ 13 июня 2011

Вы можете вызвать метод Any и передать значение для сравнения с любым свойством типа объекта в коллекции

if (!CurrentCollection.Any(f => f.bar == someValue))
{
    // add item
}

более полное решение может быть:

DownloadedItems.Where(d => !CurrentCollection.Any(c => c.bar == d.bar)).ToList()
    .ForEach(f => CurrentCollection.Add(f));
2 голосов
/ 20 сентября 2017

Или используя All

CurrentCollection
    .AddRange(DownloadedItems.Where(x => CurrentCollection.All(y => y.bar != x.bar)));
1 голос
/ 18 июня 2018

Еще одна вещь, которую вы можете сделать, и я думаю, что это самый простой способ - использовать HashSet вместо List, по умолчанию HashSet не добавляет избыточных значений.

0 голосов
/ 13 июня 2011

Вы можете сделать это так:

CurrentCollection.Any(x => x.bar == yourGivenValue)
0 голосов
/ 13 июня 2011
var newItems = DownloadedItems.Where(i => !CurrentCollection.Any(c => c.Attr == i.Attr));
...