如果通过比较项目的属性,集合尚未包含它,则将项目添加到集合中?

时间:2011-06-13 13:38:47

标签: c# linq collections contains

基本上,我如何制作它以便我可以执行类似于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?

10 个答案:

答案 0 :(得分:45)

首先找出集合中尚未包含哪些元素:

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

答案 1 :(得分:11)

使用R.Martinho Fernandes方法并转换为1行:

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

答案 2 :(得分:7)

您可以使用Enumerable.Except

它将比较两个列表并返回仅出现在第一个列表中的元素。

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

答案 3 :(得分:4)

您可以调用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));

答案 4 :(得分:2)

或使用All

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

答案 5 :(得分:1)

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

使用默认的比较结果将得出1,2,3。
如果您更改比较行为,这也将适用于Foo

    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()
    }

您还可以实现IEqualityComparer<Foo>,并将其作为第二个参数传递给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();
        }
    }

答案 6 :(得分:1)

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)....

答案 7 :(得分:0)

var newItems = DownloadedItems.Where(i => !CurrentCollection.Any(c => c.Attr == i.Attr));

答案 8 :(得分:0)

你可以这样做:

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

答案 9 :(得分:0)

您可以做的一件事我认为最简单的方法是使用HashSet而不是List,默认情况下,HashSet不会添加冗余值。