我正在尝试实现IEqualityComparer<T>
以便将Except
与复杂类型的集合一起使用。我在调试时遇到了一个奇怪的(或我不知道的平常事物)问题。我有两个馆藏的物品数量不同,如下所示。
{A, B, C, D, E}.Except({A, B}, new CustomComparer()).ToList()
通过添加ToList()
,我可以调试覆盖的Equals(x, y)
。直到项目C
都像预期的那样工作,直到项目B
之后,除外向C
发送D
和Equals(x, y)
到public SubmoduleListComparer(
Action<FormerGsdmlComparison.SubModuleListDifferenceContainer, string, string> callBack,
string firstFileName,
string secondFilename)
{
DifferenceHighlighter = callBack;
m_FirstFileName = firstFileName;
m_SecondFileName = secondFilename;
}
public bool Equals(Submodule x, Submodule y)
{
bool areEqual = true;
if (x == null || y == null) return false;
var submoduleDifferences = new FormerGsdmlComparison.SubModuleListDifferenceContainer
{
file1 = new FormerGsdmlComparison.Submodule
{
orderNumber = x.OrderNumber,
submoduleId = x.Id,
submoduleIdentNumber = x.SubmoduleIdentNumber
}
};
if (x.Id != y.Id)
{
submoduleDifferences.file2.submoduleId = y.Id;
areEqual = false;
}
if (x.OrderNumber != y.OrderNumber)
{
submoduleDifferences.file2.orderNumber = y.OrderNumber;
areEqual = false;
}
if (x.SubmoduleIdentNumber != y.SubmoduleIdentNumber)
{
submoduleDifferences.file2.submoduleIdentNumber = y.SubmoduleIdentNumber;
areEqual = false;
}
if (!areEqual)
{
DifferenceHighlighter(submoduleDifferences, m_FirstFileName, m_SecondFileName);
}
return areEqual;
}
,所以我无法区分这些元素属于第一个集合或其中一个属于第二个。
下面是我的IEqualityComparer实现。 DifferenceHighlighter是一种回调方法,为我提供了在调用者位置收集差异的方法。
Except()
如上所述,我期望null
在对第二个集合的项目进行迭代时发送Equals(x, y)
。相反,它将两个元素从第一个集合发送到first
是LINQ Except的默认行为,我应该进行更多检查还是缺少什么?
编辑
second
集合包含51个元素,而first
集合仅包含7个元素。将两个集合中的7个项目发送到Equals(x,y)之后;除了开始发送second
集合中的顺序项目。例如:
This is the debug view for first items on both collections
以上正是我所期望的。前两项属于Equals方法。但是在第7次迭代之后; items on Equals(x, y)
like that。
first
集合没有这些项目。以上各项是 $('.portfolio-slider').owlCarousel({
loop:true,
autoplay:true,
autoplayTimeout:4000,
navText:['<i class="ion-chevron-left"></i>','<i class="ion-chevron-right"></i>'],
nav:true,
responsive:{
0:{
items:1
},
}
})
$('.clients-active').owlCarousel({
loop:true,
navText:['<i class="ion-chevron-left"></i>','<i class="ion-chevron-right"></i>'],
nav:true,
autoplay:true,
autoplaySpeed:800,
autoplayTimeout:2000,
animateOut: 'fadeOut',
responsive:{
0:{
items:2
},
450:{
items:3
},
768:{
items:4
},
1000:{
items:6
}
}
})
集合的第8和第9个元素。因此,我的DifferenceHighlighter假定这些是两个集合之间的差异。
答案 0 :(得分:3)
这是预期行为; Except
使用 set (而不是 bags )(仅包含uinque物品)进行操作;因此Except
仅返回与不同的项目:
var demo = new int[] {1, 1}
.Except(new int[0])
.ToList();
Console.Write(string.Join(" ", demo));
结果:
1
在您的情况下,Except
测试项C
和D
(来自第一个集合的都是)的目的是:确保返回仅与不同的项目:
https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,e289e6c98881b2b8
static IEnumerable<TSource> ExceptIterator<TSource>(
IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer) {
Set<TSource> set = new Set<TSource>(comparer);
foreach (TSource element in second)
set.Add(element);
foreach (TSource element in first)
// Here Except tries adding element from first
// and have to compare if the element has been in set already.
// in your case 'D' will be tested on A, B (which are in second)
// and 'C' which has been added earlier
if (set.Add(element))
yield return element;
}
如果您想要first
中的“ 所有个项目(包含重复的 ),但{{1}中出现 的项目除外”,您可以手动创建second
并放置一个简单的HashSet<T>
:
Where
答案 1 :(得分:1)
事实证明,我完全误解了Except()
的目的和用法。正如克里斯(Chris)的评论和德米特里(Dmitry)对Except()
的解释的回答一样,最好使用Zip()
迭代两个集合,检测差异并将结果合并到另一个集合(或其他无数选项)中。 Except
确实可以代表其意思。经过对Zip()
简单代码示例的快速调查,该示例也符合我的条件,如下所示:
foreach (var submoduleListPairs in firstFile.SubmoduleList.Zip(secondFile.SubmoduleList, (x, y) => new { x, y }))
{
if (submoduleListPairs.x != null && submoduleListPairs.y != null)
{
if (submoduleListPairs.x.SubmoduleIdentNumber != submoduleListPairs.y.SubmoduleIdentNumber)
{
//Add differences to result collection
}
//Do other comparisons like below
}
else if (submoduleListPairs.x == null)
{
//Notate that second collection contains an item which first one not on result collection
}
else if (submoduleListPairs.y == null)
{
//Notate that first collection contains an item which second one not on result collection
}
}
这可能不是Zip()
的最佳用法,但我想展示一下它如何解决我的问题,以及为什么我不应该使用Except()
进行比较。我认为我一直坚持认为IEqualityComparer和Except是LINQ比较问题的方法。
最后编辑
Zip()
的想法令人鼓舞,但是如果其中一个集合由于其目的而超出项目范围(合并集合),则内置Zip()
会停止。因此,我进行了更深入的搜索,发现了一个很棒的SO问题和this answer。即使没有投票,也可以大大简化上述答案。