C# 比较通用集合?
我有一个C# 比较通用集合?,c#,linq,collections,C#,Linq,Collections,我有一个 ObservableCollection<BasicClass> allCollection; ObservableCollection<BasicClass> selectedCollection; 现在,我在allCollection中添加了许多BasicClass项目,并且只在selectedCollection中选择了BasicClass 我想在selectedCollection中添加allCollection中没有的项目。 我试过这个 forea
ObservableCollection<BasicClass> allCollection;
ObservableCollection<BasicClass> selectedCollection;
现在,我在allCollection
中添加了许多BasicClass
项目,并且只在selectedCollection中选择了BasicClass
我想在selectedCollection
中添加allCollection
中没有的项目。
我试过这个
foreach(var a in allCollection)
{
foreach(var s in selectedCollection)
if(a.Name!=s.Name)
//selectedCollection.Add(new BasicClass {Name =a.Name, Age=a.Age});
}
但问题是这段代码为每个不匹配的名称添加了新的BasicClass,
但我的实际要求是,对于allCollection的每个名称,比较所有selectedCollection项。如果没有,则为下一个项目添加else move。
LINQ解决方案能帮上忙吗?事实上,我通过更多的if和flags实现了这一点,但这看起来非常忙碌。
我的传统解决方案
foreach(var a in allCollection)
{
bool same = false;
foreach(var s in selectedCollection)
if(a.Name==s.Name)
same=true;
}
if(same==false)
selectedCollection.Add(new BasicClass {Name =a.Name, Age=a.Age});
我讨厌这个
编辑:
我不想比较不同的收藏。
我想比较collection1值和collection2所有值,如果没有,那么我想添加我不确定我是否正确理解了您的要求,因此我可能没有抓住要点
您的BasicClass
应该实现IEquatable
接口,这样就可以比较BasicClass
的两个实例是否相等:
class BasicClass : IEquatable<BasicClass>
{
public Name {get;set;}
public Age {get;set;}
public bool Equals(BasicClass other)
{
if (other == null)
return false;
return string.Equals(this.Name, other.Name);
}
public override int GetHashCode()
{
return Name == null ? 0 : Name.GetHashCode();
}
}
或者,您可以实现一个IEqualityComparer
并将其传递给(而不是在BasicClass
中实现IEquatable
)您是对的,使用Linq更容易实现:
var itemsToAdd = allCollection.Except(selectedCollection);
foreach (var item in itemsToAdd)
selectedCollection.Add(item);
另一方面,这将使两个列表包含完全相同的项。这是你想要的吗
如果BasicItem根据名称重写'Equals'和'GetHashCode',那么这就是您所需要的。如果没有,那么您还需要实现:
所以基本上你需要一个“where not in”?Linq->Except是在BasicClass.name上进行筛选的方法。只为Except实现IEqualityComparer。您确定不需要它吗
foreach(var a in allCollection)
{
if (!selectedCollection.Contains(a))
selectedCollection.Add(new BasicClass {Name =a.Name, Age=a.Age});
}
编辑
我刚刚看到您在下面关于仅在名称上匹配的评论,因此上面的内容并不是您真正想要的:)。请尝试以下方法:
foreach(var a in allCollection)
{
if (!selectedCollection.Any(s => a.Name == s.Name))
{
selectedCollection.Add(new BasicClass {Name =a.Name, Age=a.Age});
}
}
编辑
正如Chris所建议的,您也可以使用“除外”来创建集合。我不确定这会有多大收获,它可能会更快,但它需要编写比较器代码并创建一个新的临时集合。但是,它非常简洁,例如,一旦您编写了比较者,您只需将缺少的项目添加到集合中:
selectedCollection.Concat(allCollection.Except(selectedCollection));
“我的实际要求是,对于allCollection的每个名称,比较所有选定的集合项。如果没有,则为下一项添加else move。”--这是对过程的描述,而不是要求。常规名称比较会产生非常糟糕的键。例如,现实世界的数据通常会有同名的人。你希望如何处理这些情况?@asawyer这不是一个实际问题或senario。。。我只举了一个与我的问题相匹配的简单例子。好吧,我想我应该提一下,因为我在生产环境中遇到了类似的情况,这造成了各种各样的痛苦。我只想比较一下名字而不是年龄。如果姓名相同但年龄相同,会发生什么not@Gaps与Thomas所展示的类似,您需要重写“Equals”和“GetHashCode”,以便在比较中只使用Name。如果这不是您一直想要的行为,那么您必须实现和IQualityComparer。我将添加一些代码。“GetHashCode”也应该在示例中定义。问题是它的运行时为O(n^2),而我认为基于Linq的解决方案是O(n),因为它们使用哈希表进行set操作。这是可行的,短n sweet,但如果我们不考虑O(n^2),我会尽量在林克,你可以看看克里斯建议的“除外”方法。我怀疑这会带来巨大的不同,但我会在我的答案中添加一些代码。
var itemsToAdd = allCollections.Except(selectedCollection, new NameComparer());
foreach(var a in allCollection)
{
if (!selectedCollection.Contains(a))
selectedCollection.Add(new BasicClass {Name =a.Name, Age=a.Age});
}
foreach(var a in allCollection)
{
if (!selectedCollection.Any(s => a.Name == s.Name))
{
selectedCollection.Add(new BasicClass {Name =a.Name, Age=a.Age});
}
}
selectedCollection.Concat(allCollection.Except(selectedCollection));