Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Linq与自定义IEqualityComparer相交_C#_Linq_Intersection_Intersect - Fatal编程技术网

C# 使用Linq与自定义IEqualityComparer相交

C# 使用Linq与自定义IEqualityComparer相交,c#,linq,intersection,intersect,C#,Linq,Intersection,Intersect,长话短说:我有两个对象集合。一个包含好的值(我们称之为“好”),另一个包含默认值(Mr.“default”)。我想要好与坏,坏与坏之间的交集。换句话说:Intersect(并集(良好,默认),Default)。有人可能会认为它会解析为默认值,但这里是它变得棘手的地方:我使用一个定制的IEqualityComparer 我上了以下课程: class MyClass { public string MyString1; public string MyString2; pub

长话短说:我有两个对象集合。一个包含好的值(我们称之为“好”),另一个包含默认值(Mr.“default”)。我想要好与坏,坏与坏之间的交集。换句话说:Intersect(并集(良好,默认),Default)。有人可能会认为它会解析为默认值,但这里是它变得棘手的地方:我使用一个定制的IEqualityComparer

我上了以下课程:

class MyClass
{
    public string MyString1;
    public string MyString2;
    public string MyString3;
}

class MyEqualityComparer : IEqualityComparer<MyClass>
{
    public bool Equals(MyClass item1, MyClass item2)
    {
        if(item1 == null && item2 == null)
            return true;
        else if((item1 != null && item2 == null) ||
                (item1 == null && item2 != null))
            return false;

        return item1.MyString1.Equals(item2.MyString1) &&
               item1.MyString2.Equals(item2.MyString2);
    }

    public int GetHashCode(MyClass item)
    {
        return new { item.MyString1, item.MyString2 }.GetHashCode();
    }
}

我教过它应该是有效的,但我得到的结果基本上只是好的{MyString1,MyString2}对集,但都来自默认集,所以我有所有的默认值。我还尝试切换上一次相交的默认值和良好值,但得到了相同的结果。

首先,这是错误的:

public bool Equals(MyClass item1, MyClass item2)
{
    return GetHashCode(item1) == GetHashCode(item2);
}
如果hashcode不同,则确保相应的2项不同,但如果它们相等,则不能保证相应的2项相等

因此,这是正确的
等于
实现:

public bool Equals(MyClass item1, MyClass item2)
{
    if(object.ReferenceEquals(item1, item2))
        return true;
    if(item1 == null || item2 == null)
        return false;
    return item1.MyString1.Equals(item2.MyString1) &&
           item1.MyString2.Equals(item2.MyString2);
}
作为(预期我),代码如下:

var Default = new List<MyClass>
{
    new MyClass{MyString1="A",MyString2="A",MyString3="-"},
    new MyClass{MyString1="B",MyString2="B",MyString3="-"},
    new MyClass{MyString1="X",MyString2="X",MyString3="-"},
    new MyClass{MyString1="Y",MyString2="Y",MyString3="-"},
    new MyClass{MyString1="Z",MyString2="Z",MyString3="-"},

};
var Good = new List<MyClass>
{
    new MyClass{MyString1="A",MyString2="A",MyString3="+"},
    new MyClass{MyString1="B",MyString2="B",MyString3="+"},
    new MyClass{MyString1="C",MyString2="C",MyString3="+"},
    new MyClass{MyString1="D",MyString2="D",MyString3="+"},
    new MyClass{MyString1="E",MyString2="E",MyString3="+"},
};
var wantedResult = Good.Intersect(Default, new MyEqualityComparer())
                       .Union(Default, new MyEqualityComparer());

// wantedResult:
// A A +
// B B +
// X X -
// Y Y -
// Z Z -
var Default=新列表
{
新MyClass{MyString1=“A”,MyString2=“A”,MyString3=“-”},
新MyClass{MyString1=“B”,MyString2=“B”,MyString3=“-”},
新MyClass{MyString1=“X”,MyString2=“X”,MyString3=“-”},
新MyClass{MyString1=“Y”,MyString2=“Y”,MyString3=“-”},
新MyClass{MyString1=“Z”,MyString2=“Z”,MyString3=“-”},
};
var Good=新列表
{
新MyClass{MyString1=“A”,MyString2=“A”,MyString3=“+”},
新MyClass{MyString1=“B”,MyString2=“B”,MyString3=“+”},
新MyClass{MyString1=“C”,MyString2=“C”,MyString3=“+”},
新MyClass{MyString1=“D”,MyString2=“D”,MyString3=“+”},
新MyClass{MyString1=“E”,MyString2=“E”,MyString3=“+”},
};
var wantedResult=Good.Intersect(默认值为new MyEqualityComparer())
.Union(默认值,新的MyEqualityComparer());
//想要的结果:
//A+
//B B+
//X X-
//Y Y-
//Z Z-

您需要检查实际的相等性,而不仅仅是hashcode相等性

GetHashCode()
不是(也不能)无冲突的,这就是为什么首先需要
Equals
方法的原因

而且,你可以通过写作来更简单地做到这一点

WantedResult = Good.Concat(Default).Distinct();
Distinct
方法将返回每对副本的第一项,因此这将返回所需的结果

编辑:应该是

WantedResult = Good.Intersect(Default, new MyEqualityComparer())
                   .Union(Default, new MyEqualityComparer());

你的Equals实现非常糟糕。将出现不应该存在的哈希冲突。为什么不使用相同的投影(
new{item.MyString1,item.MyString2}
)而调用Equals呢?我应该研究一下,这可能是问题的一部分。并集使用GetHashCode,相交使用Equals。我真的没有在那部分投入任何精力。ashamedi如果我使用Concat&Distinct,我会得到我想要的结果,但我也会得到一些好的集合中不在所需范围内的项(默认)。并集和交集操作是可交换的,因此它不会更改结果,但是是的,它避免使用中间人变量。哦,等等,并集和交集不是可交换的:
(ABC u ABD)n AE=A
(ABC n AE)u ABD=ABD
哦,对不起,我只是在考虑我的情况:(ABC u ABD)n ABC=ABC和ABC u(ABD n ABC)=ABC。但是,你是对的,它们不是。在我的情况下,(ABC u ABD)!=(ABD u ABC),因为它不是一个真正的联盟。+1感谢你在我的同龄人身上帮了我很多忙,但没有被接受,因为它不能解决问题。(我希望我能+2!:-P)没问题。我为你的交叉点问题写了正确的解决方案,但Slacks期待着我。他的答案;-)我觉得很愚蠢。。。我误解了有关intersect方法的工具提示,并且我的基础数据中存在错误,因此无法进行匹配。因为我认为这篇文章是最有帮助的,随着平等和例子的实施,我接受了它。再次感谢。不客气;-)。顺便说一下,如果比较器被调用了很多次,并且性能对您来说非常重要,那么您应该考虑重写
GetHashCode()
,以避免为每次调用创建一个匿名类型的新实例。看看这个答案,可以得到一个快速有效的实现-->即Equals的实现是次优的。序言很难读。取而代之的是考虑<代码>(object .RealthyAs=(ITEM1,ITEM2))返回true;<代码>用于第一行。它处理两个都为null的情况,加快了两个都是相同引用的情况。如果(item1==null | | item2==null)返回false,则null检查的其余部分就是
更简短、更易于阅读,并且是正确的,因为如果它们都为null,则您已经返回true。
WantedResult = Good.Intersect(Default, new MyEqualityComparer())
                   .Union(Default, new MyEqualityComparer());