实现IEquatable <t>以避免从List <t> </t> </t>重复

时间:2011-10-19 13:58:56

标签: c#

我有List<CustomObject>并希望从中删除重复项。
如果两个自定义对象具有相同的property: City值,那么我将其称为重复 我已经实现了如下IEquatable,但是无法从列表中删除重复项。

缺少什么?

 public class CustomAddress : IAddress, IEqualityComparer<IAddress>
 {
    //Other class members go here

    //IEqualityComparer members
    public bool Equals(IAddress x, IAddress y)
    {
        // Check whether the compared objects reference the same data.
        if (ReferenceEquals(x, y)) return true;

        // Check whether any of the compared objects is null.
        if (ReferenceEquals(x, null) || ReferenceEquals(y, null))
            return false;

        // Check whether the Objects' properties are equal.
        return x.City.Equals(y.City);

    }

    public int GetHashCode(IAddress obj)
    {
        // Check whether the object is null.
        if (ReferenceEquals(obj, null)) return 0;

        int hashAreaName = City == null ? 0 : City.GetHashCode();
        return hashAreaName;
    }
 }

我正在使用.NET 3.5

4 个答案:

答案 0 :(得分:1)

如果你有EqualsGetHashCode的覆盖,如果你有一个需要过滤的现有列表,只需调用Distinct()(可通过命名空间System.Linq获得)清单。

var noDupes = list.Distinct();

这将为您提供无重复的序列。如果您需要将其作为具体列表,只需在调用结束时添加ToList()即可。

var noDupes = list.Distinct().ToList();

另一个答案提到实施IEqualityComparer<CustomObject>。当直接覆盖EqualsGetHashCode是不可能的(你不控制源代码)或没有意义时(在这种特殊情况下你的平等概念对于类来说不是通用的),这很有用。在这种情况下,定义比较器as demonstrated并将比较器的实例提供给Distinct的重载。

最后,如果您要从头开始构建列表并希望避免插入重复项,则可以使用HashSet<T>,如上所述here。 HashSet还在构造函数中接受自定义比较器,因此您可以选择包含它。

var mySet = new HashSet<CustomObject>();
bool isAdded = mySet.Add(myElement); 
// isAdded will be false if myElement already exists in set, and 
// myElement would not be added a second time.
// or you could use 
if (!mySet.Contains(myElement))
     mySet.Add(myElement);

另一个不使用.NET库方法但在紧要关头可用的选项是Jon Skeet的DistinctBy,您可以看到粗略的实现here。我们的想法是您直接提交Func<MyObject, Key> lambda表达式,并完全忽略EqualsGetHashCode(或自定义比较器)的覆盖。

 var noDupes = list.DistinctBy(obj => obj.City); // NOT part of BCL

答案 1 :(得分:0)

要仅在特定属性上匹配重复项,您需要比较器。

class MyComparer : IEqualityComparer<CustomObject>
{
    public bool Equals(CustomObject x, CustomObject y)
    {
        return x.City.Equals(y.City);
    }

    public int GetHashCode(CustomObject x)
    {
        return x.City.GetHashCode()
    }
}

用法:

var yourDistictObjects = youObjects.Distinct(new MyComparer()); 

编辑:找到了能够满足您需求的线程,我想我过去曾提到过它:

Remove duplicates in the list using linq

我认为一个有趣的答案(但不是如何做到的)是:

var distinctItems = items.GroupBy(x => x.Id).Select(y => y.First());

这是一个可以满足您需要的单线,但可能没有其他方法那么高效。

答案 2 :(得分:0)

只需按照您的方式实施.Equals(如果您正确实施),就不会阻止将重复项添加到List<T>。您实际上必须手动删除它们。

而不是List<CustomObject>使用HashSet<CustomObject>。它永远不会包含重复项。

答案 3 :(得分:0)

那是因为List<CustomObject>会测试您的班级(CustomObject)是否实施IEquatable<CustomObject>而不是IEquatable<IAddress>

我认为在添加新成员之前,对于重复检查,您使用的是Contains方法