web-dev-qa-db-fra.com

Ajouter des éléments à une collection si la collection ne le contient pas déjà en comparant une propriété des éléments?

Fondamentalement, comment puis-je le faire pour que je puisse faire quelque chose de similaire à: CurrentCollection.Contains(...), sauf en comparant si la propriété de l'élément est déjà dans la collection?

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?
28
michael

Vous commencez par trouver quels éléments ne sont pas déjà dans la collection:

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

Et puis ajoutez-les simplement:

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

Notez que la première opération peut avoir une complexité quadratique si la taille de DownloadedItems est proche de celle de CurrentCollection. Si cela pose problème (mesurez d'abord!), Vous pouvez utiliser un HashSet pour ramener la complexité à linéaire:

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

Utilisation de la méthode R.Martinho Fernandes et conversion en 1 ligne:

CurrentCollection.AddRange(DownloadedItems.Where(x => !CurrentCollection.Any(y => y.bar== x.bar)));
10
JumpingJezza

Vous pouvez utiliser Enumerable.Except

Il comparera les deux listes et renverra les éléments qui apparaissent uniquement dans la première liste.

CurrentCollection.AddRange(DownloadedItems.Except(CurrentCollection));
6
Yanga

Vous pouvez appeler la méthode Any et transmettre une valeur à comparer à n'importe quelle propriété du type d'objet de la collection.

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

une solution plus complète pourrait être:

DownloadedItems.Where(d => !CurrentCollection.Any(c => c.bar == d.bar)).ToList()
    .ForEach(f => CurrentCollection.Add(f));
4
hunter

Ou en utilisant All 

CurrentCollection
    .AddRange(DownloadedItems.Where(x => CurrentCollection.All(y => y.bar != x.bar)));
2
Janis S.

Une des choses que vous pouvez faire est de penser que le moyen le plus simple est de créer un HashSet au lieu d’une Liste. Par défaut, le HashSet n’ajoute pas de valeurs redondantes. 

0
Khalil Liraqui
var newItems = DownloadedItems.Where(i => !CurrentCollection.Any(c => c.Attr == i.Attr));
0
Bala R

Vous pouvez le faire comme ceci: 

CurrentCollection.Any(x => x.bar == yourGivenValue)
0
ub1k