C# 在列表中查找不同的点(使用2个谓词)

C# 在列表中查找不同的点(使用2个谓词),c#,linq,duplicates,C#,Linq,Duplicates,假设我有一个自定义“点”类的列表(我知道System.Drawing中有一个,但假设我需要一个自定义类)。现在这个列表有时可能有相同的点,例如,假设它是这样设置的: List<customPoint> myPoints = new List<customPoint>(); myPoints.Add(new customPoint(1,5)); myPoints.Add(new customPoint(1,5)); myPoints.Add(new customPoint(

假设我有一个自定义“点”类的列表(我知道System.Drawing中有一个,但假设我需要一个自定义类)。现在这个列表有时可能有相同的点,例如,假设它是这样设置的:

List<customPoint> myPoints = new List<customPoint>();
myPoints.Add(new customPoint(1,5));
myPoints.Add(new customPoint(1,5));
myPoints.Add(new customPoint(2,3));
myPoints.Add(new customPoint(4,9));
myPoints.Add(new customPoint(8,7));
myPoints.Add(new customPoint(2,3));
List myPoints=new List();
添加(新的customPoint(1,5));
添加(新的customPoint(1,5));
添加(新的customPoint(2,3));
添加(新的customPoint(4,9));
添加(新的customPoint(8,7));
添加(新的customPoint(2,3));
后来我需要做一些计算,但我不需要重复。有什么比这更优雅的方法来创建一个新的独特点列表:

List<customPoint> uniquePoints = new List<customPoint>();

for(int i; i < myPoints.Count; i++)
{
    Boolean foundDuplicate = false;    

    int tempX = myPoints[i].X;
    int tempY = myPoints[i].Y;        

    for(int j=0; j < uniquePoints.Count; j++)
    {
        if((tempX == uniquePoints[0].X) && (tempY == uniquePoints[0].Y))
        {
            foundDuplicate = true;
            break;
        }            
    }
    if(!foundDuplicate)
    {
        uniquePoints.Add(myPoints[i]);
    }        
}
List uniquePoints=new List();
for(int i;i

我知道这很混乱,但这就是为什么我问是否有更优雅的方式。我查看了Linq“Distinct”命令,但它似乎不起作用,我想在它们的对象实例化中仍然有一些独特的地方。

您尝试使用Linq做了哪些不起作用的事情?下面的代码应该可以做到这一点:

var uniquePoints = myPoints.Distinct();
该方法将是一个很好的方法,但为了按您的意愿使用它,您必须在对象上实现
Equals
GetHashCode
,或者创建一个
IEqualityComparer
并将其传递到
Distinct
方法中。对于您的情况,在对象上实现这些方法可能是有意义的。从文件中:

默认的相等比较器用于比较 实现泛型接口的类型。到 比较自定义数据类型,您需要实现此接口和 提供您自己的类型和方法

1)将这些方法添加到您的
customPoint

public override int GetHashCode()
{
    return X.GetHashCode() * 19 + Y.GetHashCode();
}

public override bool Equals(object obj)
{
    var other = obj as customPoint;
    return this.X == other.X && this.Y == other.Y;
}
您可以使用Linq的
Distinct
方法

var distinctPoints = myPoints.Distinct().ToList();

2)您可以在不重写任何方法的情况下使用匿名类型比较技巧

var distinctPoints = myPoints.GroupBy(m => new { m.X, m.Y })
                             .Select(x => x.First())
                             .ToList();

3)您也可以通过编写自定义的
IEqualityComparer

public class MyEqualityComparer : IEqualityComparer<customPoint>
{
    public bool Equals(customPoint a, customPoint b)
    {
        return a.X == b.X && a.Y == b.Y;
    }

    public int GetHashCode(customPoint other)
    {
        return other.X.GetHashCode() * 19 + other.Y.GetHashCode();
    }
}

var distinctPoints = myPoints.Distinct(new MyEqualityComparer()).ToList();
公共类MyEqualityComparer:IEqualityComparer
{
公共布尔等于(自定义点a、自定义点b)
{
返回a.X==b.X&&a.Y==b.Y;
}
public int GetHashCode(customPoint其他)
{
返回other.X.GetHashCode()*19+other.Y.GetHashCode();
}
}
var distinctPoints=myPoints.Distinct(新的MyEqualityComparer()).ToList();

我是在LinqPad中这样做的,所以请原谅
转储()
…但是这里有一种方法可以实现您的
customPoint
类:

void Main()
{
    var myPoints = new List<customPoint>();
    myPoints.Add(new customPoint(1,5));
    myPoints.Add(new customPoint(1,5));
    myPoints.Add(new customPoint(2,3));
    myPoints.Add(new customPoint(4,9));
    myPoints.Add(new customPoint(8,7));
    myPoints.Add(new customPoint(2,3));

    myPoints.Distinct().Dump();
}


public class customPoint {
    public int X;
    public int Y;

    public customPoint(int x, int y){
        X = x;
        Y = y;
    }

    public override Boolean Equals(Object rhs) {
        var theObj = rhs as customPoint;

        if(theObj==null) {
            return false;
        } else {
            return theObj.X == this.X && theObj.Y == this.Y;
        }
    }

    public override int GetHashCode() {
        return X ^ Y;
    }
}
void Main()
{
var myPoints=新列表();
添加(新的customPoint(1,5));
添加(新的customPoint(1,5));
添加(新的customPoint(2,3));
添加(新的customPoint(4,9));
添加(新的customPoint(8,7));
添加(新的customPoint(2,3));
myPoints.Distinct().Dump();
}
公共类海关关卡{
公共int X;
公共智力;
公共自定义点(整数x,整数y){
X=X;
Y=Y;
}
公共覆盖布尔等于(对象rhs){
var theObj=rhs作为自定义点;
if(theObj==null){
返回false;
}否则{
返回theObj.X==this.X&&theObj.Y==this.Y;
}
}
公共覆盖int GetHashCode(){
返回X^Y;
}
}

我怀疑OP调用了
myPoints.Distinct()
并忽略了返回值。或者他没有正确地覆盖Equals/GetHashCode,当然:)@JonSkeet确实如此,至少在GetHashCode上,我不知道我可以覆盖它,直到我问了这个问题。我按照阿贝·米斯勒的建议做了,但没有凌驾于那些建议之上,这是行不通的。你如何生成一个散列,这样就不太可能得到不同的点,并且有唯一的代码,特别是当我比较(2,1)和(1,2)时?这里有一个到前面讨论的链接,以及到distinctDoes your
customPoint
类上msdn文档的链接(哪一个应该是
CustomPoint
以遵循命名约定)适当地覆盖
Equals
GetHashCode
?我已经完成了Equals(但使用了IEquatable),但不是散列码。我也研究过GroupBy,但在理解以类似方式使用它的其他问题的语法时有点困难。我对散列码有点陌生,所以我很好奇,为什么在这种情况下X乘以19?@xantam这是一个随机素数,如果你写
返回0; 。一个好的散列算法可能会提高性能,仅此而已。您需要确保的是,如果两个对象相等,则它们的散列码必须相同。(但不一定相反)啊,这很有意义。谢谢。