使用映射从点集合中删除重复项
本文关键字:删除 集合 映射 点集 | 更新日期: 2023-09-27 18:25:34
我有一个点数组,我们称之为rawPoints,它包含重复项。事实上,几乎每个点都重复 2 到 6 次。在某处重复,而不是在连续的位置。我想删除重复项以获得一个新的集合,我称之为 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。
是否存在类似的东西,或者是否有其他简单且相当快速的解决方案?
虽然HashSet<Point>
不会帮助在goodPoints
中找到唯一的索引,但Dictionary<Point,int>
会。
除了 List<Point> goodPoints
之外,创建一个字典Dictionary<Point,int> mappings
,将指向列表中的索引映射到goodPoints
索引。当您遍历rawPoints
数组时,请遵循以下算法:
- 检查
rawPoints[i]
是否在mappings
。如果是,请继续到下一点 - 否则,将当前长度的
goodPoints
添加到rawPoints[i]
的mappings
,然后将rawPoints[i]
添加到gooodPoints
列表中。
假设您的Point
表示形式具有良好的哈希函数,并且它正确地覆盖了Equals
,则此算法会生成goodPoints
列表和 O(N( 中的映射。
您将需要两个输出:
- "好点"列表。 将索引数组映射到良好点数组中,
- 其长度与原始点相同(因为您希望将每个原始点索引映射到良好点数组中(。
我认为这段代码将生成这两件事:
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;
}
}
}
您可以使用 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));
}
您可以创建一个 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();