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

Posted

技术标签:

【中文标题】如果集合尚未通过比较项目的属性将项目添加到集合中?【英文标题】:Add items to a collection if the collection does NOT already contain it by comparing a property of the items? 【发布时间】:2011-09-13 22:38:12 【问题描述】:

基本上,我该怎么做才能做到类似于: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?

【问题讨论】:

【参考方案1】:

您可以调用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】:
var newItems = DownloadedItems.Where(i => !CurrentCollection.Any(c => c.Attr == i.Attr));

【讨论】:

【参考方案3】:

你可以这样做:

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

【讨论】:

【参考方案4】:

您首先要查找集合中尚未包含的元素:

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

【讨论】:

使用 hash-map 方法使我的方法快了 5 倍。 我认为这是最好的做法【参考方案5】:

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

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

【讨论】:

【参考方案6】:

或者使用All

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

【讨论】:

【参考方案7】:

你可以使用Enumerable.Except:

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

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

【讨论】:

【参考方案8】:

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

【讨论】:

【参考方案9】:
    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&lt;Foo&gt;,并将其作为第二个参数传递给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();
        
    

【讨论】:

【参考方案10】:
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)....

【讨论】:

以上是关于如果集合尚未通过比较项目的属性将项目添加到集合中?的主要内容,如果未能解决你的问题,请参考以下文章

通过 REST 调用使用外键将项目添加到集合中

通过 REST 调用使用外键将项目添加到集合中

与采集订购骨干共同意见

UICollectionView:在指定索引处添加项目并滚动到该项目

循环记录集并添加到字典/集合:项目键存在

将项目添加到集合后主干和车把呈现问题