如果集合尚未通过比较项目的属性将项目添加到集合中?
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<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();
【讨论】:
【参考方案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)....
【讨论】:
以上是关于如果集合尚未通过比较项目的属性将项目添加到集合中?的主要内容,如果未能解决你的问题,请参考以下文章