如何从嵌套对象列表中删除重复项?
How to remove duplicates from a list of nested objects?
我知道有很多答案建议覆盖 equals 和 hashcode,但就我而言,这是不可能的,因为所使用的对象是从 DLL 导入的。
首先,我有一个名为 DeploymentData
的对象列表。
这些对象以及其他属性包含以下两个:Location(double x, double y, double z)
和 Duct(int id)
。
目标是删除具有相同 Location
参数的那些。
首先,我按 Duct
对它们进行分组,因为 Location
如果在另一个管道上则不能相同。
var groupingByDuct = deploymentDataList.GroupBy(x => x.Duct.Id).ToList();
那么实际的算法:
List<DeploymentData> uniqueDeploymentData = new List<DeploymentData>();
foreach (var group in groupingByDuct) {
uniqueDeploymentData
.AddRange(group
.Select(x => x)
.GroupBy(d => new { d.Location.X, d.Location.Y, d.Location.Z })
.Select(x => x.First()).ToList());
}
这确实有效,但为了正确检查它们是否确实重复,应该比较整个位置。为此,我做了以下方法:
private bool CompareXYZ(XYZ point1, XYZ point2, double tolerance = 10)
{
if (System.Math.Abs(point1.X - point2.X) < tolerance &&
System.Math.Abs(point1.Y - point2.Y) < tolerance &&
System.Math.Abs(point1.Z - point2.Z) < tolerance) {
return true;
}
return false;
}
但是 我不知道如何将它应用到上面编写的代码中。总结:
- 如何在不调用所有这些方法的情况下编写上述算法?
- 如何调整上述算法以使用
CompareXYZ
方法以获得更好的精度?
- 效率?
过滤重复项的一种简单方法是使用具有自定义相等比较器的哈希集。这是实现 IEqualityComparer 的 class,例如:
public class DeploymentDataEqualityComparer : IEqualityComparer<DeploymentData>
{
private readonly double _tolerance;
public DeploymentDataEqualityComparer(double tolerance)
{
_tolerance = tolerance;
}
public bool Equals(DeploymentData a, DeploymentData b)
{
if (a.Duct.id != b.Duct.id)
return false; // Different Duct, therefore not equal
if (System.Math.Abs(a.Location.X - b.Location.X) < _tolerance &&
System.Math.Abs(a.Location.Y - b.Location.Y) < _tolerance &&
System.Math.Abs(a.Location.Z - b.Location.Z) < _tolerance) {
return true;
}
return false;
}
public GetHashCode(DeploymentData dd)
{
// If the classes of the library do not implement GetHashCode, you can create a custom implementation
return dd.Duct.GetHashCode() | dd.Location.GetHashCode();
}
}
为了过滤重复项,您可以将它们添加到 HashSet 中:
var hashSet = new HashSet<DeploymentData>(new DeploymentDataEqualityComparer(10));
foreach (var deploymentData in deploymentDataList)
hashSet.Add(deploymentData);
这样就不需要通过管道分组,也不需要使用HashSet的增强性能。
我知道有很多答案建议覆盖 equals 和 hashcode,但就我而言,这是不可能的,因为所使用的对象是从 DLL 导入的。
首先,我有一个名为 DeploymentData
的对象列表。
这些对象以及其他属性包含以下两个:Location(double x, double y, double z)
和 Duct(int id)
。
目标是删除具有相同 Location
参数的那些。
首先,我按 Duct
对它们进行分组,因为 Location
如果在另一个管道上则不能相同。
var groupingByDuct = deploymentDataList.GroupBy(x => x.Duct.Id).ToList();
那么实际的算法:
List<DeploymentData> uniqueDeploymentData = new List<DeploymentData>();
foreach (var group in groupingByDuct) {
uniqueDeploymentData
.AddRange(group
.Select(x => x)
.GroupBy(d => new { d.Location.X, d.Location.Y, d.Location.Z })
.Select(x => x.First()).ToList());
}
这确实有效,但为了正确检查它们是否确实重复,应该比较整个位置。为此,我做了以下方法:
private bool CompareXYZ(XYZ point1, XYZ point2, double tolerance = 10)
{
if (System.Math.Abs(point1.X - point2.X) < tolerance &&
System.Math.Abs(point1.Y - point2.Y) < tolerance &&
System.Math.Abs(point1.Z - point2.Z) < tolerance) {
return true;
}
return false;
}
但是 我不知道如何将它应用到上面编写的代码中。总结:
- 如何在不调用所有这些方法的情况下编写上述算法?
- 如何调整上述算法以使用
CompareXYZ
方法以获得更好的精度? - 效率?
过滤重复项的一种简单方法是使用具有自定义相等比较器的哈希集。这是实现 IEqualityComparer 的 class,例如:
public class DeploymentDataEqualityComparer : IEqualityComparer<DeploymentData>
{
private readonly double _tolerance;
public DeploymentDataEqualityComparer(double tolerance)
{
_tolerance = tolerance;
}
public bool Equals(DeploymentData a, DeploymentData b)
{
if (a.Duct.id != b.Duct.id)
return false; // Different Duct, therefore not equal
if (System.Math.Abs(a.Location.X - b.Location.X) < _tolerance &&
System.Math.Abs(a.Location.Y - b.Location.Y) < _tolerance &&
System.Math.Abs(a.Location.Z - b.Location.Z) < _tolerance) {
return true;
}
return false;
}
public GetHashCode(DeploymentData dd)
{
// If the classes of the library do not implement GetHashCode, you can create a custom implementation
return dd.Duct.GetHashCode() | dd.Location.GetHashCode();
}
}
为了过滤重复项,您可以将它们添加到 HashSet 中:
var hashSet = new HashSet<DeploymentData>(new DeploymentDataEqualityComparer(10));
foreach (var deploymentData in deploymentDataList)
hashSet.Add(deploymentData);
这样就不需要通过管道分组,也不需要使用HashSet的增强性能。