【问题标题】:Getting List of Objects that occurs exaclty twice in a list获取列表中恰好出现两次的对象列表
【发布时间】:2012-12-07 22:44:16
【问题描述】:

我有一个List<CustomPoint> points;,其中包含近百万个对象。 从这个列表中,我想获得恰好出现两次的对象列表。最快的方法是什么?我也会对非 Linq 选项感兴趣,因为我可能也必须在 C++ 中执行此操作。

public class CustomPoint
{
    public double X { get; set; }
    public double Y { get; set; }

    public CustomPoint(double x, double y)
    {
        this.X = x;
        this.Y = y;
    }
}

public class PointComparer : IEqualityComparer<CustomPoint>
{
    public bool Equals(CustomPoint x, CustomPoint y)
    {
        return ((x.X == y.X) && (y.Y == x.Y));
    }

    public int GetHashCode(CustomPoint obj)
    {
        int hash = 0;
        hash ^= obj.X.GetHashCode();
        hash ^= obj.Y.GetHashCode();
        return hash;
    }
}

基于this的回答,我试过了,

list.GroupBy(x => x).Where(x => x.Count() = 2).Select(x => x.Key).ToList(); 

但这在新列表中给出了零个对象。 有人可以指导我吗?

【问题讨论】:

  • 你从哪里得到数据?
  • @MichaelPerrenoud - 这些是地理纬度和经度值
  • 是的,但是从哪里加载数据(例如 SQL Server 数据库)?我问是因为您提到它接近一百万个对象,而且您可能需要在 C++ 中访问它
  • @MichaelPerrenoud - 好的..我正在从 shapefile (en.wikipedia.org/wiki/Shapefile) 中读取这些点。我正在使用一个名为 Quantum GIS 的应用程序及其 C++ API..
  • 你可能知道也可能不知道,但是比较双精度数是否相等通常不是一个好主意。见stackoverflow.com/questions/1398753/…

标签: c# duplicates


【解决方案1】:

你应该在类本身而不是在 PointComparer 中实现 Equals 和 GetHashCode

【讨论】:

  • 我为点类实现了 IEqualityComparer..它没有工作..我一定做错了什么
  • 不,没关系,但是你可以用另一种方式使用,但是如果你想使用equals和gethashcode方法,你必须在主类而不是IEqualityComparer上使用它们
【解决方案2】:

要使您的代码正常工作,您需要将PointComparer 的实例作为第二个参数传递给GroupBy

【讨论】:

  • 我试过 points.GroupBy(new PointComparer()).Where(g => g.Count() == 2).Select(g => g.Key).ToList();它不编译
  • 抱歉,您需要 lambda new PointComparer()(两个参数)。
【解决方案3】:

这个方法对我有用:

public class PointCount
{
    public CustomPoint Point { get; set; }
    public int Count { get; set; }
}

private static IEnumerable<CustomPoint> GetPointsByCount(Dictionary<int, PointCount> pointcount, int count)
{
    return pointcount
                    .Where(p => p.Value.Count == count)
                    .Select(p => p.Value.Point);
}

private static Dictionary<int, PointCount> GetPointCount(List<CustomPoint> pointList)
{
    var allPoints = new Dictionary<int, PointCount>();

    foreach (var point in pointList)
    {
        int hash = point.GetHashCode();

        if (allPoints.ContainsKey(hash))
        {
            allPoints[hash].Count++;
        }
        else
        {
            allPoints.Add(hash, new PointCount { Point = point, Count = 1 });
        }
    }

    return allPoints;
}

这样称呼:

static void Main(string[] args)
{
    List<CustomPoint> list1 = CreateCustomPointList();

    var doubles = GetPointsByCount(GetPointCount(list1), 2);

    Console.WriteLine("Doubles:");
    foreach (var point in doubles)
    {
        Console.WriteLine("X: {0}, Y: {1}", point.X, point.Y);
    }
}

private static List<CustomPoint> CreateCustomPointList()
{
    var result = new List<CustomPoint>();

    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            result.Add(new CustomPoint(i, j));
        }
    }

    result.Add(new CustomPoint(1, 3));
    result.Add(new CustomPoint(3, 3));
    result.Add(new CustomPoint(0, 2));

    return result;
}

CustomPoint 实现:

public class CustomPoint
{
    public double X { get; set; }
    public double Y { get; set; }

    public CustomPoint(double x, double y)
    {
        this.X = x;
        this.Y = y;
    }

    public override bool Equals(object obj)
    {
        var other = obj as CustomPoint;

        if (other == null)
        {
            return base.Equals(obj);
        }

        return ((this.X == other.X) && (this.Y == other.Y));
    }

    public override int GetHashCode()
    {
        int hash = 23;
        hash = hash * 31 + this.X.GetHashCode();
        hash = hash * 31 + this.Y.GetHashCode();
        return hash;
    }
}

打印出来:

Doubles:
X: 0, Y: 2
X: 1, Y: 3
X: 3, Y: 3

正如您在GetPointCount() 中看到的,我为每个唯一的CustomPoint 创建一个字典(通过哈希)。然后我插入一个PointCount 对象,其中包含对CustomPoint 的引用,该引用从Count 1 开始,每次遇到相同点时,Count 都会增加。

最后在GetPointsByCount 中,我在PointCount.Count == count 的字典中返回CustomPoints,在你的情况下是2。

还请注意,我更新了GetHashCode() 方法,因为您的方法对点 (1,2) 和 (2,1) 返回相同。如果您确实需要,请随时恢复您自己的哈希方法。不过,您将不得不测试散列函数,因为很难将两个数字唯一地散列为一个。这取决于使用的数字范围,因此您应该实现一个适合您自己需求的哈希函数。

【讨论】:

  • 这和我的回答一样,但是有代码,不需要代码,他可以很容易地写代码,然后你的时间
  • @MSakherSawan “这与我的答案相同” - 不,不是,我实现了 GetDoubles() 方法,与您的答案相反,它确实回答了问题.
  • @flindeberg 确实如此,但您必须同步字典访问以防止并发问题。不知道您是否会从中受益匪浅。
  • @CodeCaster 我在 map-reduce 方面考虑得更多 :) 但这当然取决于原始数据的组成,如果有很多相似的点 map-reduce 真的会有所帮助,但是如果没有它真的不会。
  • @vinayan CodeCaster 对GetHashCode 的实现 故意 避免这样做,因为通常这是一个坏主意;如果您想要是这种情况,那么只需将他的GetHashCode 替换为您的问题中的那个。
猜你喜欢
  • 2014-11-25
  • 2021-12-12
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2020-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多