在删除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();
但两者都以与之前相同的条件返回列表,只是重复项。
您需要覆盖/实现Equals()
和GetHashCode()
,现在您正在列出不同的实例,并且它们正确地彼此不同/唯一
您遇到的问题是对象的身份不是您想的那样。你的直觉告诉你恒等式是firstParam
和secondParam
的组合。真正发生的是className
的每个不同实例都有自己的标识,而不依赖于对象的实现。您将需要覆盖通过System.Object
提供的方法,主要是Equals
和GetHashCode
,尽管您可能不覆盖GetHashCode
(这将需要哈希集正常工作)
如果你的类只包含这两个字段,那么不是实现Equals
和GetHashCode
,你也可以这样做:
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());
上面的代码将对属性firstParam
和secondParam
进行分组,稍后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());
这允许你在一次射击中区分物体,而不需要执行Equals
和GetHashCode
。如果,例如,在项目中有一个地方,在那里你调用这样的Distinct
,这可能足以使用这个扩展。另一方面,如果className
对象的标识是一个跨越许多方法和类的概念,那么肯定最好只定义Equals
和GetHashCode
。