Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.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# 查找具有公差的唯一对象列表_C#_Distinct - Fatal编程技术网

C# 查找具有公差的唯一对象列表

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识别为同一点,并且只将其中一个保留在唯一列表中唉,

我有一个点列表,我只想从中提取唯一的元素。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识别为同一点,并且只将其中一个保留在唯一列表中

唉,即使在最简单的
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();