获取 LIST<T> 区别的通用方法
Generic Method to get Distinct of LIST<T>
我正在尝试比较(属性值)列表中的类型实例并消除重复项。
根据 MSDN GetHashCode() 是比较两个对象的方法之一。
A hash code is intended for efficient insertion and lookup in
collections that are based on a hash table. A hash code is not a
permanent value
考虑到这一点,我开始如下编写我的扩展方法
public static class Linq
{
public static IEnumerable<T> DistinctObjects<T>(this IEnumerable<T> source)
{
List<T> newList = new List<T>();
foreach (var item in source)
{
if(newList.All(x => x.GetHashCode() != item.GetHashCode()))
newList.Add(item);
}
return newList;
}
}
这个条件总是给我 false
尽管对象的数据是相同的。
newList.All(x => x.GetHashCode() != item.GetHashCode())
终于想用起来了
MyDuplicateList.DistinctObjects().ToList();
如果比较对象的所有字段太多了,我可以这样使用它,
MyDuplicateList.DistinctObjects(x=>x.Id, x.Name).ToList();
这里我说的是只比较那些对象的这两个字段。
您不需要为此创建自己的自定义通用方法。相反,为您的数据类型提供自定义 EqualityComparar
:
var myDuplicates = myList.Distinct(new MyComparer());
在哪里定义自定义比较器,如下所示:
public class MyComparer : IEqualityComparer<Mine>
{
public bool Equals(Mine x, Mine y)
{
if (x == null && y == null) return true;
if (x == null || y == null) return false;
return x.Name == y.Name && x.Id == y.Id;
}
public int GetHashCode(Mine obj)
{
return obj.Name.GetHashCode() ^ obj.Id.GetHashCode();
}
}
编辑:我最初在这里的代码不正确,这应该可以完成您想要的操作,而无需覆盖 Equals
运算符
阅读您的评论后,我会提出这个解决方案:
public static IEnumerable<TSource> DistinctBy<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
HashSet<TResult> set = new HashSet<TResult>();
foreach(var item in source)
{
var selectedValue = selector(item);
if (set.Add(selectedValue))
yield return item;
}
}
然后你可以这样使用它:
var distinctedList = myList.DistinctBy(x => x.A);
或像这样的多个属性:
var distinctedList = myList.DistinctBy(x => new {x.A,x.B});
此解决方案的优点是您可以准确指定应该使用哪些属性来区分,而不必为每个对象覆盖 Equals
和 GetHashCode
。您需要确保您的属性可以进行比较。
我正在尝试比较(属性值)列表中的类型实例并消除重复项。 根据 MSDN GetHashCode() 是比较两个对象的方法之一。
A hash code is intended for efficient insertion and lookup in collections that are based on a hash table. A hash code is not a permanent value
考虑到这一点,我开始如下编写我的扩展方法
public static class Linq
{
public static IEnumerable<T> DistinctObjects<T>(this IEnumerable<T> source)
{
List<T> newList = new List<T>();
foreach (var item in source)
{
if(newList.All(x => x.GetHashCode() != item.GetHashCode()))
newList.Add(item);
}
return newList;
}
}
这个条件总是给我 false
尽管对象的数据是相同的。
newList.All(x => x.GetHashCode() != item.GetHashCode())
终于想用起来了
MyDuplicateList.DistinctObjects().ToList();
如果比较对象的所有字段太多了,我可以这样使用它,
MyDuplicateList.DistinctObjects(x=>x.Id, x.Name).ToList();
这里我说的是只比较那些对象的这两个字段。
您不需要为此创建自己的自定义通用方法。相反,为您的数据类型提供自定义 EqualityComparar
:
var myDuplicates = myList.Distinct(new MyComparer());
在哪里定义自定义比较器,如下所示:
public class MyComparer : IEqualityComparer<Mine>
{
public bool Equals(Mine x, Mine y)
{
if (x == null && y == null) return true;
if (x == null || y == null) return false;
return x.Name == y.Name && x.Id == y.Id;
}
public int GetHashCode(Mine obj)
{
return obj.Name.GetHashCode() ^ obj.Id.GetHashCode();
}
}
编辑:我最初在这里的代码不正确,这应该可以完成您想要的操作,而无需覆盖 Equals
运算符
阅读您的评论后,我会提出这个解决方案:
public static IEnumerable<TSource> DistinctBy<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
HashSet<TResult> set = new HashSet<TResult>();
foreach(var item in source)
{
var selectedValue = selector(item);
if (set.Add(selectedValue))
yield return item;
}
}
然后你可以这样使用它:
var distinctedList = myList.DistinctBy(x => x.A);
或像这样的多个属性:
var distinctedList = myList.DistinctBy(x => new {x.A,x.B});
此解决方案的优点是您可以准确指定应该使用哪些属性来区分,而不必为每个对象覆盖 Equals
和 GetHashCode
。您需要确保您的属性可以进行比较。