对LINQ和对象使用Distinct
直到最近,我还在使用LINQ中的Distinct从表中选择一个不同的类别(枚举)。这很好用 我现在需要在一个包含类别和国家(都是枚举)的类上对其进行区分。分离机现在不工作了对LINQ和对象使用Distinct,linq,distinct,Linq,Distinct,直到最近,我还在使用LINQ中的Distinct从表中选择一个不同的类别(枚举)。这很好用 我现在需要在一个包含类别和国家(都是枚举)的类上对其进行区分。分离机现在不工作了 我做错了什么?我相信这篇文章解释了你的问题: 上面链接的内容可以总结为,Distinct()方法可以通过执行以下操作来替换 var distinctItems = items .GroupBy(x => x.PropertyToCompare) .Select(x => x.Firs
我做错了什么?我相信这篇文章解释了你的问题: 上面链接的内容可以总结为,Distinct()方法可以通过执行以下操作来替换
var distinctItems = items
.GroupBy(x => x.PropertyToCompare)
.Select(x => x.First());
试试液体比较法
public class MyObjEqualityComparer : IEqualityComparer<MyObj>
{
public bool Equals(MyObj x, MyObj y)
{
return x.Category.Equals(y.Category) &&
x.Country.Equals(y.Country);
}
public int GetHashCode(MyObj obj)
{
return obj.GetHashCode();
}
}
有关解释,请看其他答案。我只是提供一种处理这个问题的方法 您可能会喜欢:
注意:只对LINQ2对象可靠地工作您没有做错,这只是.NET Framework中
.Distinct()
的糟糕实现
修复它的一种方法已在其他答案中显示,但也有一种较短的解决方案可用,其优点是您可以在任何地方轻松地将其用作扩展方法,而无需调整对象的哈希值
看看这个:
**用法:** 注意:此示例使用数据库查询,但它也适用于可枚举对象列表。
MyDistinct的声明:
public static class Extensions
{
public static IEnumerable<T> MyDistinct<T, V>(this IEnumerable<T> query,
Func<T, V> f)
{
return query.GroupBy(f).Select(x=>x.First());
}
}
公共静态类扩展
{
公共静态IEnumerable MyDistinct(此IEnumerable查询,
函数(f)
{
return query.GroupBy(f).Select(x=>x.First());
}
}
或者,如果您希望它更短,则与上面相同,但为“一行”:
公共静态IEnumerable MyDistinct(此IEnumerable查询,Func f)
=>query.GroupBy(f).选择(x=>x.First());
它适用于任何事物,对象和实体。如果需要,您可以为
IQueryable
创建第二个重载扩展方法,只需替换我上面给出的示例中的返回类型和第一个参数类型。我知道这是一个老问题,但我对任何答案都不满意。我花了一些时间来为自己解决这个问题,我想分享我的发现
首先,阅读和理解这两件事很重要:长话短说为了使
.Distinct()
扩展理解如何确定对象的相等性,您必须为对象T定义一个“相等比较程序”。当您阅读Microsoft文档时,它会逐字说明:
我们建议您从EqualityComparer类派生
而不是实现IEqualityComparer接口
这就是你决定使用什么的方式,因为它已经为你决定了
要使.Distinct()
扩展成功工作,您必须确保可以准确地比较对象。在.Distinct()
的情况下,真正重要的是GetHashCode()
方法
您可以自己编写一个GetHashCode()
实现来测试这一点,该实现只返回传入对象的当前哈希代码,您将看到结果不好,因为该值在每次运行时都会更改。这使得您的对象过于独特,这就是为什么实际编写此方法的正确实现非常重要的原因
下面是IEqualityComparer
页面上的代码示例的精确副本,其中包含测试数据、对GetHashCode()
方法的小修改以及用于说明这一点的注释
//Did this in LinqPad
void Main()
{
var lst = new List<Box>
{
new Box(1, 1, 1),
new Box(1, 1, 1),
new Box(1, 1, 1),
new Box(1, 1, 1),
new Box(1, 1, 1)
};
//Demonstration that the hash code for each object is fairly
//random and won't help you for getting a distinct list
lst.ForEach(x => Console.WriteLine(x.GetHashCode()));
//Demonstration that if your EqualityComparer is setup correctly
//then you will get a distinct list
lst = lst
.Distinct(new BoxEqualityComparer())
.ToList();
lst.Dump();
}
public class Box
{
public Box(int h, int l, int w)
{
this.Height = h;
this.Length = l;
this.Width = w;
}
public int Height { get; set; }
public int Length { get; set; }
public int Width { get; set; }
public override String ToString()
{
return String.Format("({0}, {1}, {2})", Height, Length, Width);
}
}
public class BoxEqualityComparer
: EqualityComparer<Box>
{
public override bool Equals(Box b1, Box b2)
{
if (b2 == null && b1 == null)
return true;
else if (b1 == null || b2 == null)
return false;
else if (b1.Height == b2.Height && b1.Length == b2.Length
&& b1.Width == b2.Width)
return true;
else
return false;
}
public override int GetHashCode(Box bx)
{
#region This works
//In this example each component of the box object are being XOR'd together
int hCode = bx.Height ^ bx.Length ^ bx.Width;
//The hashcode of an integer, is that same integer
return hCode.GetHashCode();
#endregion
#region This won't work
//Comment the above lines and uncomment this line below if you want to see Distinct() not work
//return bx.GetHashCode();
#endregion
}
}
//这是在LinqPad中完成的
void Main()
{
var lst=新列表
{
新盒子(1,1,1),
新盒子(1,1,1),
新盒子(1,1,1),
新盒子(1,1,1),
新盒子(1,1,1)
};
//演示每个对象的哈希代码是否正确
//随机的,不会帮助你得到一个明确的列表
lst.ForEach(x=>Console.WriteLine(x.GetHashCode());
//演示EqualityComparer是否正确设置
//然后您将得到一个不同的列表
lst=lst
.Distinct(新的BoxEqualityComparer())
.ToList();
lst.Dump();
}
公共类箱
{
公用箱(内部h、内部l、内部w)
{
这个高度=h;
这个。长度=l;
这个。宽度=w;
}
公共整数高度{get;set;}
公共整数长度{get;set;}
公共整数宽度{get;set;}
公共重写字符串ToString()
{
返回String.Format(({0},{1},{2})”,高度、长度、宽度);
}
}
公共类拳击手
:相等比较
{
公共覆盖布尔等于(框b1、框b2)
{
如果(b2==null&&b1==null)
返回true;
else if(b1==null | | b2==null)
返回false;
如果(b1.Height==b2.Height&&b1.Length==b2.Length
&&b1.宽度==b2.宽度)
返回true;
其他的
返回false;
}
公共覆盖int GetHashCode(框bx)
{
#这个区域有效
//在本例中,box对象的每个组件都是异或的
int hCode=bx.高度^bx.长度^bx.宽度;
//整数的哈希代码,就是同一个整数
返回hCode.GetHashCode();
#端区
#这是行不通的
//如果希望看到Distinct()不起作用,请对上面的行进行注释,并取消对下面这行的注释
//返回bx.GetHashCode();
#端区
}
}
请不要仅通过链接来回答。答案中包含了相关代码。是的,我不再这样做了,但在2010年我没有注意到这种做法。我喜欢这种解决方案,但我有一个问题。GetHashCode导致它找不到匹配项。我不得不将其更改为类似于return obj.Category.GetHashCode()+obj.Country.GetHashCode()
public void Foo{
public string Fizz{get;set;}
public BarEnum Bar{get;set;}
}
public enum BarEnum {One,Two,Three}
var lst=new List<Foo>();
lst.Distinct(new LambdaComparer<Foo>(
(x1,x2)=>x1.Fizz==x2.Fizz&&
x1.Bar==x2.Bar));
public static class EnumerableExtensions{
public static IEnumerable<T> SmartDistinct<T>
(this IEnumerable<T> lst, Func<T, T, bool> pred){
return lst.Distinct(new LambdaComparer<T>(pred));
}
}
lst.SmartDistinct((x1,x2)=>x1.Fizz==x2.Fizz&&x1.Bar==x2.Bar);
var myQuery=(from x in Customers select x).MyDistinct(d => d.CustomerID);
public static class Extensions
{
public static IEnumerable<T> MyDistinct<T, V>(this IEnumerable<T> query,
Func<T, V> f)
{
return query.GroupBy(f).Select(x=>x.First());
}
}
public static IEnumerable<T> MyDistinct<T, V>(this IEnumerable<T> query, Func<T, V> f)
=> query.GroupBy(f).Select(x => x.First());
//Did this in LinqPad
void Main()
{
var lst = new List<Box>
{
new Box(1, 1, 1),
new Box(1, 1, 1),
new Box(1, 1, 1),
new Box(1, 1, 1),
new Box(1, 1, 1)
};
//Demonstration that the hash code for each object is fairly
//random and won't help you for getting a distinct list
lst.ForEach(x => Console.WriteLine(x.GetHashCode()));
//Demonstration that if your EqualityComparer is setup correctly
//then you will get a distinct list
lst = lst
.Distinct(new BoxEqualityComparer())
.ToList();
lst.Dump();
}
public class Box
{
public Box(int h, int l, int w)
{
this.Height = h;
this.Length = l;
this.Width = w;
}
public int Height { get; set; }
public int Length { get; set; }
public int Width { get; set; }
public override String ToString()
{
return String.Format("({0}, {1}, {2})", Height, Length, Width);
}
}
public class BoxEqualityComparer
: EqualityComparer<Box>
{
public override bool Equals(Box b1, Box b2)
{
if (b2 == null && b1 == null)
return true;
else if (b1 == null || b2 == null)
return false;
else if (b1.Height == b2.Height && b1.Length == b2.Length
&& b1.Width == b2.Width)
return true;
else
return false;
}
public override int GetHashCode(Box bx)
{
#region This works
//In this example each component of the box object are being XOR'd together
int hCode = bx.Height ^ bx.Length ^ bx.Width;
//The hashcode of an integer, is that same integer
return hCode.GetHashCode();
#endregion
#region This won't work
//Comment the above lines and uncomment this line below if you want to see Distinct() not work
//return bx.GetHashCode();
#endregion
}
}