C# 查找具有公差的唯一对象列表
我有一个点列表,我只想从中提取唯一的元素。point类如下所示C# 查找具有公差的唯一对象列表,c#,distinct,C#,Distinct,我有一个点列表,我只想从中提取唯一的元素。point类如下所示 class Point { double X; double Y; double Z; } 现在,两个点,例如p1(1,2,3)和p2(1.01,2,3.01)应视为同一点。这是一种宽容。现在由于公差,我不能使用c#distinct()方法或任何使用hascode的函数。有没有任何可能的方法可以让我不必使用Bruteforce方法就可以得到唯一列表,并将p1和p2识别为同一点,并且只将其中一个保留在唯一列表中唉,
class Point
{
double X;
double Y;
double Z;
}
现在,两个点,例如p1(1,2,3)和p2(1.01,2,3.01)应视为同一点。这是一种宽容。现在由于公差,我不能使用c#distinct()方法或任何使用hascode的函数。有没有任何可能的方法可以让我不必使用Bruteforce方法就可以得到唯一列表,并将p1和p2识别为同一点,并且只将其中一个保留在唯一列表中唉,即使在最简单的1d
情况下也不可能(让所有点的Y
和Z
相等)。
我们可以用矛盾来证明它;设e
为正公差,这意味着
p1 ~ p2
无论何时
|p1.X - p2.X| <= e
所以我们有
|A.X - B.X| = e <= e, so A ~ B
|B.X - C.X| = e <= e, so B ~ C
编辑:您可以尝试将缩放作为部分解决方案。如果点位于同一(超)立方体e*e*…*e
其中比例因子e
是某种“公差”。那么,为了
我们可以实现如下等式比较器:
public class PointEqualityComparer : IEqualityComparer<Point> {
private double m_Scale;
private long Scale(double value) => (long)Math.Round(value / m_Scale);
public PointEqualityComparer(double scale) {
m_Scale = scale > 0
? scale
: throw new ArgumentOutOfRangeException(nameof(scale));
}
public bool Equals(Point left, Point right) {
if (ReferenceEquals(left, right))
return true;
else if (null == left || null == right)
return false;
return Scale(left.X) == Scale(right.X) &&
Scale(left.Y) == Scale(right.Y) &&
Scale(left.Z) == Scale(right.Z);
}
public int GetHashCode(Point obj) => obj == null
? 0
: Scale(obj.X).GetHashCode() ^
Scale(obj.Y).GetHashCode() ^
Scale(obj.Z).GetHashCode();
}
公共类PointEqualityComparer:IEqualityComparer{
私人双m_量表;
专用长标度(双值)=>(长)数学舍入(值/m_标度);
公共点均衡比较器(双刻度){
m_比例=比例>0
规模
:抛出新ArgumentOutOfRangeException(nameof(scale));
}
公共布尔等于(左点,右点){
if(ReferenceEquals(左、右))
返回true;
else if(null==左| | null==右)
返回false;
返回刻度(左.X)=刻度(右.X)&&
比例(左Y)=比例(右Y)&&
刻度(左Z)=刻度(右Z);
}
public int GetHashCode(点obj)=>obj==null
? 0
:Scale(obj.X).GetHashCode()^
Scale(obj.Y).GetHashCode()^
Scale(obj.Z).GetHashCode();
}
用法
List original=。。。
列表唯一=原始
.Distinct(新的PointEqualityComparer(1e-3))
.ToList();
另一种流行的方法——集群——可能很难实现。首先,将点分组为簇(可以是巨大的,形状不同等),然后从每个簇中提取“典型代表”(例如,位于簇边界上的所有点)。实现
IEquatable
接口,覆盖两种方法Equals
和GetHashCode
,据解释,您也可以使用自定义和重载。但我如何编写允许容差的gethashcode?@nandini banerjee:gethashcode()=>0
很难看,毫无用处,但它是哈希函数的正确实现(允许容差)。真正的问题是我们无法实现Equals
方法,因为不可能按等价进行分组(由@DmitryBychenko清楚地显示),您要搜索的是“聚类算法”。有一些常用的数据分析,也许你可以看看那里。
|A.X - C.X| = 2 * e > e, so A !~ C
class Point
{
double X;
double Y;
double Z;
}
public class PointEqualityComparer : IEqualityComparer<Point> {
private double m_Scale;
private long Scale(double value) => (long)Math.Round(value / m_Scale);
public PointEqualityComparer(double scale) {
m_Scale = scale > 0
? scale
: throw new ArgumentOutOfRangeException(nameof(scale));
}
public bool Equals(Point left, Point right) {
if (ReferenceEquals(left, right))
return true;
else if (null == left || null == right)
return false;
return Scale(left.X) == Scale(right.X) &&
Scale(left.Y) == Scale(right.Y) &&
Scale(left.Z) == Scale(right.Z);
}
public int GetHashCode(Point obj) => obj == null
? 0
: Scale(obj.X).GetHashCode() ^
Scale(obj.Y).GetHashCode() ^
Scale(obj.Z).GetHashCode();
}
List<Point> original = ...
List<Point> unique = original
.Distinct(new PointEqualityComparer(1e-3))
.ToList();