【问题标题】:Remove duplicates from a list containing a generic class从包含泛型类的列表中删除重复项
【发布时间】:2015-10-08 13:14:33
【问题描述】:

我正在尝试从包含泛型类的列表中删除重复项。泛型类看起来像这样(剥离示例):

public class Point2D<T>
{
    public T x;
    public T y;

    public Point2D(T x, T y)
    {
        this.x = x;
        this.y = y;
    }
}

我已经创建了这样的列表:

List<Point2D<int>> pointList = new List<Point2D<int>>();
pointList.Add(new Point2D<int>(1,1));
pointList.Add(new Point2D<int>(1,2));
pointList.Add(new Point2D<int>(1,1));
pointList.Add(new Point2D<int>(1,3));

我尝试通过以下方式删除重复项:

pointList = pointList.Distinct().ToList();

预计pointList 将只包含:(1,1)、(1,2)、(1,3),但它仍然包含输入的所有四个点。我怀疑在Point2D 中我需要自己的equals 或comparator 方法,但我不知道是否是这种情况,或者它们应该如何编写(当然,除非我只是遗漏了一些简单的东西)。

【问题讨论】:

    标签: c# .net generics


    【解决方案1】:

    为此,您需要重写Equals 方法:

        public class Point2D<T>
        {
            public readonly T x;
            public readonly T y;
    
            public Point2D(T x, T y)
            {
                this.x = x;
                this.y = y;
            }
            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((Point2D<T>) obj);
            }
    
            protected bool Equals(Point2D<T> other)
            {
                return EqualityComparer<T>.Default.Equals(x, other.x) && EqualityComparer<T>.Default.Equals(y, other.y);
            }
    
            public override int GetHashCode()
            {
                unchecked
                {
                    return (EqualityComparer<T>.Default.GetHashCode(x)*397) ^ EqualityComparer<T>.Default.GetHashCode(y);
                }
            }
        }
    

    另外,您需要覆盖GetHashCode。但要正确执行此操作,您必须将 xy 设为只读字段

    【讨论】:

    • 好老头,嗯?
    • @Blorgbeard 是的,它让这些事情变得又快又容易
    • @Backs 我不确定 GetHashCode 方法,所以必须阅读它,但这允许我的单元测试通过。谢谢。
    • 你真的不应该基于可变值实现GetHashCode,因为来自GetHashCode的值在对象的生命周期内永远不应该改变。这个对象应该是不可变的,这是一个很好的答案。
    • @Enigmativity 是的,是的。我真的忘记了这件事。更新了只读字段
    【解决方案2】:

    您可以使用匿名对象。这将如何改变参考。所以只有在不需要以前的参考资料时才使用它。

    pointList = pointList.Select(x => new {x.x,x.y}).Distinct().Select(x => new Point2D<int>(x.x, x.y)).ToList();
    

    【讨论】:

    • new {x.x,x.y} 在做什么?那是什么类型的?
    • @Ayb4btu 具有只读属性的自定义编译时类型。 new {x.x,x.y} 的名称和类型由编译器在编译时生成。阅读更多关于匿名对象msdn.microsoft.com/en-us/library/bb397696.aspx
    【解决方案3】:

    你需要实现

    IEquatable<T>
    

    这个自定义类的接口。查看此链接以获取更多详细信息和示例:

    https://msdn.microsoft.com/en-us/library/vstudio/bb348436(v=vs.100).aspx

    【讨论】:

      【解决方案4】:

      我建议覆盖 == 运算符。 This 应该会有所帮助。

      【讨论】:

      • 这没有提供问题的答案。要批评或要求作者澄清,请在其帖子下方发表评论。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-16
      • 1970-01-01
      • 1970-01-01
      • 2012-09-09
      • 2018-05-13
      • 1970-01-01
      • 2019-09-18
      相关资源
      最近更新 更多