Add items to a collection if the collection does NOT already contain it by comparing a property of the items?

Viewed 89025

Basically, how do I make it so I can do something similar to: CurrentCollection.Contains(...), except by comparing if the item's property is already in the 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?
10 Answers

You can use Enumerable.Except:

It will compare the two lists and return elements that appear only in the first list.

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

Or using All

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

One thing that you can do also i think it is the easiest way is to une a HashSet instead of a List, by default the HashSet don't add redundant values.

    List<int> current = new List<int> { 1, 2 };
    List<int> add = new List<int> { 2, 3 };
    current.AddRange(add.Except(current));

This will result in 1,2,3, using the default comparing.
This will also work for Foo if you change the compare behaviour:

    public class Foo : IEquatable<Foo>
    {
        public Int32 bar;
        public bool Equals(Foo other)
        {
            return bar == other.bar;
        }
        public override bool Equals(object obj) => Equals(obj as Foo);
        public override int GetHashCode() => (bar).GetHashCode(); // (prop1,prop2,prop3).GetHashCode()
    }

You could also implement an IEqualityComparer<Foo>, and pass it as second parameter to except

    current.AddRange(add.Except(current, new FooComparer()));

    public class FooComparer : IEqualityComparer<Foo>
    {
        public bool Equals(Foo x, Foo y)
        {
            return x.bar.Equals(y.bar);
        }
        public int GetHashCode(Foo obj)
        {
            return obj.bar.GetHashCode();
        }
    }
internal static class ExtensionMethod
{
    internal static ICollection<T> AddIfExists<T>(this ICollection<T> list, ICollection<T> range)
    {
        foreach (T item in range)
        {
            if (!list.Contains(item))
                list.Add(item);
        }
        return list;
    }
}

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

CurrentCollection.AddIfExists(DownloadedItems)....
Related