使用映射从点集合中删除重复项

时间:2015-12-03 14:24:52

标签: c# collections

我有一系列点,我们称之为rawPoints,其中包含重复项。实际上,几乎每个点都重复了2到6次。重复某处,而不是在连续的位置。我想删除重复项以获得一个新的集合,我称之为goodPoints。另外,我想知道从rawPoints到goodPoints的映射。换句话说,对于rawPoints中的每个点P,我想知道(唯一)索引i,使得goodPoints [i] = P.

我在C#编码,所以我想知道是否有任何.NET集合可以帮助解决这个问题。

我读过使用HashSet是删除重复项的好方法。但那不会给我映射。

一种可能的解决方案是" AddorFind(P)"我可以用来向goodPoints添加点P的函数。如果P还不是goodPoints的成员,那么AddorFind(P)将添加它。如果P已经是goodPoints的成员,则AddorFind(P)将返回索引i,使得goodPoints [i] = P.

是否存在类似的东西,或者是否有其他简单且合理的快速解决方案?

4 个答案:

答案 0 :(得分:3)

虽然HashSet<Point>无法在goodPoints中找到唯一索引,但Dictionary<Point,int>会。{/ p>

除了List<Point> goodPoints之外,还要创建一个字典Dictionary<Point,int> mappings,将点映射到goodPoints列表中的索引。当您浏览rawPoints数组时,请遵循以下算法:

  • 检查rawPoints[i]是否在mappings。如果是,请继续下一步
  • 否则,将goodPoints的当前长度添加到mappings的{​​{1}},然后将rawPoints[i]添加到rawPoints[i]列表。

假设您的gooodPoints表示具有良好的哈希函数,并且它正确地覆盖Point,则此算法会生成Equals列表和O(N)中的映射

答案 1 :(得分:2)

您需要两个输出:

  1. &#34;好点&#34;列表。
  2. 良好点数组中的索引数组,与原始点的长度相同(因为您希望将每个原始点索引映射到优点数组中)。
  3. 我认为这段代码会生成这两件事:

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    
    namespace Demo
    {
        class Program
        {
            static void Main()
            {
                var rawPoints = createRandomPoints(10000, 100, 100);
    
                int[] goodPointMap = new int[rawPoints.Length];
                var map = new Dictionary<Point, int>();
                var goodPoints = new List<Point>();
    
                for (int i = 0; i < rawPoints.Length; ++i)
                {
                    Point p = rawPoints[i];
                    int index;
    
                    if (map.TryGetValue(p, out index))
                    {
                        goodPointMap[i] = index;
                    }
                    else
                    {
                        map[p] = goodPoints.Count;
                        goodPointMap[i] = goodPoints.Count;
                        goodPoints.Add(p);
                    }
                }
    
                // At this point we no longer need 'map', which is used only to generate 'goodPoints[]'
                // and 'goodPointMap[]'.
    
                Console.WriteLine("Number of good points = " + goodPoints.Count);
    
                // Every point in rawPoints[] should have a point in goodPoints
                // which you can reference via goodPointMap[].
                // Let's verify that:
    
                for (int i = 0; i < rawPoints.Length; ++i)
                    if (rawPoints[i] != goodPoints[goodPointMap[i]])
                        Console.WriteLine("Failed!");
            }
    
            static Point[] createRandomPoints(int n, int maxX, int maxY)
            {
                var rng    = new Random();
                var result = new Point[n];
    
                for (int i = 0; i < n; ++i)
                    result[i] = new Point(rng.Next(maxX), rng.Next(maxY));
    
                return result;
            }
        }
    }
    

答案 2 :(得分:1)

您可以使用Linq:

完成此操作
List<Point> points = new List<Point>();
points.Add(new Point(1, 1));
points.Add(new Point(1, 1));
points.Add(new Point(1, 1));
points.Add(new Point(1, 2));
points.Add(new Point(1, 2));
points.Add(new Point(1, 2));

List<Point> goodPoints = new List<Point>();


foreach (Point p in points)
{
    goodPoints.Add(p);
    //goodPoints = goodPoints.Distinct().ToList();
    //int idx = goodPoints.IndexOf(p);
    int idx = (goodPoints = goodPoints.Distinct().ToList()).IndexOf(p);
    Debug.WriteLine(string.Format("Index of Point({0}, {1}) = {2}", p.X, p.Y, idx));
}

答案 3 :(得分:0)

您可以创建一个PointComparer类,并在Distinct方法中使用它。

public class PointComparer : IEqualityComparer<Point>
{
    public bool Equals(Point p1, Point p2)
    {
        return p1.x==p2.x && p1.y == p2.y;
    }
    public int GetHashCode(Point p1)
    {
        return p1.x*p2.x;//bla bla
    }
}

goodPoints = rawPoints.Distinct(new PointComparer()).ToList();