在删除List中的重复项时遇到麻烦

本文关键字:麻烦 遇到 List 删除 class | 更新日期: 2023-09-27 18:10:31

我有一个类和列表:

    public class className
    {
        public string firstParam { get; set; }
        public string secondParam { get; set; }
    }
    public static List<className> listName = new List<className>();

该列表包括(例如):

Apple    Banana
Corn     Celery
Corn     Celery
Corn     Grapes
Raisins  Pork

我正在尝试编辑列表(或创建一个新列表)以获得:

Apple    Banana
Corn     Celery
Corn     Grapes
Raisins  Pork

I have try:

var listNoDupes = listName.Distinct();

:

IEnumerable<className> listNoDupes = listName.Distinct();

但两者都以与之前相同的条件返回列表,只是重复项。

在删除List<class>中的重复项时遇到麻烦

您需要覆盖/实现Equals()GetHashCode(),现在您正在列出不同的实例,并且它们正确地彼此不同/唯一

您遇到的问题是对象的身份不是您想的那样。你的直觉告诉你恒等式是firstParamsecondParam的组合。真正发生的是className的每个不同实例都有自己的标识,而不依赖于对象的实现。您将需要覆盖通过System.Object提供的方法,主要是EqualsGetHashCode,尽管您可能不覆盖GetHashCode(这将需要哈希集正常工作)

如果你的类只包含这两个字段,那么不是实现EqualsGetHashCode,你也可以这样做:

var listNoDupes = listName.GroupBy(r => new { r.firstParam, r.secondParam })
                        .Select(grp => grp.First())
                        .ToList();

或者你可以得到一个IEnumerable<T>返回:

IEnumerable<className> listNoDupes = 
                       listName
                           .GroupBy(r => new { r.firstParam, r.secondParam })
                           .Select(grp => grp.First());

上面的代码将对属性firstParamsecondParam进行分组,稍后grp.First将从组中返回单个项目,并且您将从每个组中返回单个项目,(没有重复)

还有第三种可能-使用Distinct方法版本,它接受IEqualityComparer。不幸的是,c#不支持创建匿名的临时接口实现。我们可以创建辅助类和扩展:

public static class IEnumerableExtensions
{
    public class LambdaEqualityComparer<T> : IEqualityComparer<T>
    {
        private Func<T, T, bool> comparer;
        private Func<T, int> hash;
        public LambdaEqualityComparer(Func<T, T, bool> comparer, 
                                      Func<T, int> hash)
        {
            this.comparer = comparer;
            this.hash = hash;
        }
        public bool Equals(T x, T y)
        {
            return comparer(x, y);
        }
        public int GetHashCode(T x)
        {
            return hash(x);
        }
    }
    public static IEnumerable<T> Distinct<T>(this IEnumerable<T> elems,
                                             Func<T, T, bool> comparer,
                                             Func<T, int> hash)
    {
        return elems.Distinct(new LambdaEqualityComparer<T>(comparer, hash));
    }
}

,然后我们可以为Distinct方法提供lambda:

var filteredList = myList.Distinct((x, y) => x.firstParam == y.firstParam &&
                                             x.secondParam == y.secondParam,
                                    x => 17 * x.firstParam.GetHashCode() + x.secondParam.GetHashCode());

这允许你在一次射击中区分物体,而不需要执行EqualsGetHashCode。如果,例如,在项目中有一个地方,在那里你调用这样的Distinct,这可能足以使用这个扩展。另一方面,如果className对象的标识是一个跨越许多方法和类的概念,那么肯定最好只定义EqualsGetHashCode