删除List <object> </object>的重复对

时间:2014-07-20 08:18:51

标签: c# wpf list duplicates

问题

我在3D WPF库中使用简单的线条显示几何体。它的一个例子可以在下一张图片中看到:

enter image description here

在其中您可以看到一组三角形和四边形。我绘制这个的方式是我提供List<Point3D>,其中我放置了代表每个段的点对。

问题是有很多重复的边缘,我想避免这种情况,因为这种类型的表示似乎非常需要资源。

生成点列表,迭代每个包含N个顶点的Element。它不知道是否共享特定边缘。

  

<p0, p1, p1, p2, p2, p333, p333, p89, p89, p2, p2, p1 ...>

想法是删除重复的对(注意顺序可能不一样)。在上面的示例中,移除的对应该是最后一个(p2,p1),因为它表示与第二对点(p1,p2)相同的边。可能有一对,两个或更多重复的点对。

我需要尽快完成此操作,性能在这里是最重要的。

在列表中添加点时,我可以临时存储其中的两个并检查列表是否已经包含它们,但是这意味着每次添加点时都会查看列表并且对我来说似乎不是一个好主意(该列表将包含数千个点5000-50000)。

我生成点列表的元素有几个具有唯一ID的节点,因此我认为可以通过创建Dictionary有序Tuple<Point3D, Point3D>然后删除重复项来以某种方式使用它。 / p>

我还没有尝试过最后一个想法,因为我还不知道如何实现它,我想知道是否还有其他事情可以做。

2 个答案:

答案 0 :(得分:3)

您可以使用HashSet存储所有边缘。检查速度快,边缘已经设置好了。但您应该覆盖GetHashCodeEquals。我做了一个简单的例子。

class MyLine
{
    public MyPoint P1 { get; private set; }
    public MyPoint P2 { get; private set; }
    public MyLine(MyPoint p1, MyPoint p2)
    {
        P1 = p1;
        P2 = p2;
    }
    protected bool Equals(MyLine other)
    {
        return (Equals(P1, other.P1) && Equals(P2, other.P2)) || Equals(P1, other.P2) && Equals(P2, other.P1);
    }
    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((MyLine)obj);
    }
    public override int GetHashCode()
    {
        unchecked
        {
            return P1.GetHashCode() + P2.GetHashCode();
        }
    }
}
class MyPoint
{
    public string Id { get; private set; }
    public MyPoint(string id)
    {
        Id = id;
    }
    protected bool Equals(MyPoint other)
    {
        return string.Equals(Id, other.Id);
    }
    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((MyPoint)obj);
    }
    public override int GetHashCode()
    {
        return (Id != null ? Id.GetHashCode() : 0);
    }
}

那么你应该能够像这样添加每一行:

public static void Main(string[] args)
{
    HashSet<MyLine> lines = new HashSet<MyLine>();
    var line = new MyLine(new MyPoint("a"), new MyPoint("b"));
    lines.Add(line);
    line = new MyLine(new MyPoint("b"), new MyPoint("a"));
    lines.Add(line);
}

同样使用GetHashCodeEquals,您可以将所有行存储在List中,然后使用Distinct方法。

public static void Main(string[] args)
{
    List<MyLine> lines = new List<MyLine>();
    var line = new MyLine(new MyPoint("a"), new MyPoint("b"));
    lines.Add(line);
    line = new MyLine(new MyPoint("b"), new MyPoint("a"));
    lines.Add(line);
    lines = lines.Distinct().ToList();
}

答案 1 :(得分:1)

使用HashSet<Tuple<Point3D, Point3D>>。每当你得到一个新的边缘 - p1,p2时,检查集合中是否存在(p1,p2)。还要检查(p2,p1)是否存在。如果两者都不存在,则将(p1,p2)和(p2,p1)添加到集合中并使用边缘。

您可以通过制作自己的哈希和相等函数来进一步加快速度,这些函数将看到(p1,p2)等于(p2,p1)。除非你需要,否则不要这样做,Set操作非常快,我怀疑改进是否相当可观。