如何很好的使用Linq的linq select distinctt方法

Linq的Distinct太不给力了
假设我们有一个类:Product
public class Product
&&& public string Id { }
&&& public string Name { }
}Main函数如下:
static void Main()
&&& List&Product& products = new List&Product&()
&&&&&&& new Product(){ Id=&1&, Name=&n1&},
&&&&&&& new Product(){ Id=&1&, Name=&n2&},
&&&&&&& new Product(){ Id=&2&, Name=&n1&},
&&&&&&& new Product(){ Id=&2&, Name=&n2&},
&&& var distinctProduct = products.Distinct();
&&& Console.ReadLine();
可以看到distinctProduct 的结果是:
因为Distinct 默认比较的是Product对象的引用,所以返回4条数据。
那么如果我们希望返回Id唯一的product,那么该如何做呢?
Distinct方法还有另一个重载:
//通过使用指定的System.Collections.Generic.IEqualityComparer&T& 对值进行比较
//返回序列中的非重复元素。
&public static IEnumerable&TSource& Distinct&TSource&(this IEnumerable&TSource& source, IEqualityComparer&TSource& comparer);该重载接收一个IEqualityComparer的参数。
假设要按Id来筛选,那么应该新建类ProductIdComparer 内容如下:
public class ProductIdComparer : IEqualityComparer&Product&
&&& public bool Equals(Product x, Product y)
&&&&&&& if (x == null)
&&&&&&&&&&& return y ==
&&&&&&& return x.Id == y.Id;
&&& public int GetHashCode(Product obj)
&&&&&&& if (obj == null)
&&&&&&&&&&& return 0;
&&&&&&& return obj.Id.GetHashCode();
}使用的时候,只需要
var distinctProduct = products.Distinct(new ProductIdComparer());结果如下:
现在假设我们要 按照Name来筛选重复呢?
很明显,需要再添加一个类ProductNameComparer.
那能不能使用泛型类呢??
新建类PropertyComparer&T& 继承IEqualityComparer&T& 内容如下:
public class PropertyComparer&T& : IEqualityComparer&T&
&&& private PropertyInfo _PropertyI
&&& /// &summary&
&&& /// 通过propertyName 获取PropertyInfo对象&&&&&&& /// &/summary&
&&& /// &param name=&propertyName&&&/param&
&&& public PropertyComparer(string propertyName)
&&&&&&& _PropertyInfo = typeof(T).GetProperty(propertyName,
&&&&&&& BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public);
&&&&&&& if (_PropertyInfo == null)
&&&&&&&&&&& throw new ArgumentException(string.Format(&{0} is not a property of type {1}.&,
&&&&&&&&&&&&&&& propertyName, typeof(T)));
&&& #region IEqualityComparer&T& Members
&&& public bool Equals(T x, T y)
&&&&&&& object xValue = _PropertyInfo.GetValue(x, null);
&&&&&&& object yValue = _PropertyInfo.GetValue(y, null);
&&&&&&& if (xValue == null)
&&&&&&&&&&& return yValue ==
&&&&&&& return xValue.Equals(yValue);
&&& public int GetHashCode(T obj)
&&&&&&& object propertyValue = _PropertyInfo.GetValue(obj, null);
&&&&&&& if (propertyValue == null)
&&&&&&&&&&& return 0;
&&&&&&& else
&&&&&&&&&&& return propertyValue.GetHashCode();
&&& #endregion
主要是重写的Equals 和GetHashCode 使用了属性的值比较。
使用的时候,只需要:
//var distinctProduct = products.Distinct(new PropertyComparer&Product&(&Id&));
var distinctProduct = products.Distinct(new PropertyComparer&Product&(&Name&));
结果如下:
为什么微软不提供PropertyEquality&T& 这个类呢?
按照上面的逻辑,这个类应该没有很复杂啊,细心的同学可以发现PropertyEquality 大量的使用了反射。每次获取属性的值的时候,都在调用
_PropertyInfo.GetValue(x, null);
可想而知,如果要筛选的记录非常多的话,那么性能无疑会受到影响。
为了提升性能,可以使用表达式树将反射调用改为委托调用,
具体代码如下:
public class FastPropertyComparer&T& : IEqualityComparer&T&
&&& private Func&T, Object& getPropertyValueFunc =
&&& /// &summary&
&&& /// 通过propertyName 获取PropertyInfo对象
&&& /// &/summary&
&&& /// &param name=&propertyName&&&/param&
&&& public FastPropertyComparer(string propertyName)
&&&&&&& PropertyInfo _PropertyInfo = typeof(T).GetProperty(propertyName,
&&&&&&& BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public);
&&&&&&& if (_PropertyInfo == null)
&&&&&&&&&&& throw new ArgumentException(string.Format(&{0} is not a property of type {1}.&,
&&&&&&&&&&&&&&& propertyName, typeof(T)));
&&&&&&& ParameterExpression expPara = Expression.Parameter(typeof(T), &obj&);
&&&&&&& MemberExpression me = Expression.Property(expPara, _PropertyInfo);
&&&&&&& getPropertyValueFunc = Expression.Lambda&Func&T, object&&(me, expPara).Compile();
&&& #region IEqualityComparer&T& Members
&&& public bool Equals(T x, T y)
&&&&&&& object xValue = getPropertyValueFunc(x);
&&&&&&& object yValue = getPropertyValueFunc(y);
&&&&&&& if (xValue == null)
&&&&&&&&&&& return yValue ==
&&&&&&& return xValue.Equals(yValue);
&&& public int GetHashCode(T obj)
&&&&&&& object propertyValue = getPropertyValueFunc(obj);
&&&&&&& if (propertyValue == null)
&&&&&&&&&&& return 0;
&&&&&&& else
&&&&&&&&&&& return propertyValue.GetHashCode();
&&& #endregion
可以看到现在获取值只需要getPropertyValueFunc(obj) 就可以了。
使用的时候:
var distinctProduct = products.Distinct(new FastPropertyComparer&Product&(&Id&)).ToList();
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'Person1: Id=1, Name=&Test1&
Person2: Id=1, Name=&Test1&
Person3: Id=2, Name=&Test2&
以上list如果直接使用distinct方法进行过滤,仍然返回3条数据,而需要的结果是2条数据。下面给出解这个问题的方法:
方法1:&&方法中使用的相等比较器。这个比较器需要重写Equals和GetHashCode方法,个人不推荐,感觉较麻烦,需要些多余的类,并且用起来还要实例化一个比较器,当然自己也可以写一个泛型的比较器生成工厂用来专门生成比较器,但仍然觉得较麻烦。
& & & & & & & MSDN给出的做法,具体参照:
方法2:自己扩展一个DistinctBy。这个扩展方法还是很不错的,用起来很简洁,适合为框架添加的Distinct扩展方法。
public static IEnumerable&TSource& DistinctBy&TSource, TKey& (this IEnumerable&TSource& source, Func&TSource, TKey& keySelector)
HashSet&TKey& seenKeys = new HashSet&TKey&();
foreach (TSource element in source)
if (seenKeys.Add(keySelector(element)))
使用方法如下(针对ID,和Name进行Distinct):
var query = people.DistinctBy(p =& new { p.Id, p.Name });
若仅仅针对ID进行distinct:
var query = people.DistinctBy(p =& p.Id);
方法3:通过GroupBy分组后,并取出第一条数据。简单易用,很方便。这是一种迂回策略,代码理解起来没有Distinct表意清晰,虽然实现了效果。
List&Person& distinctPeople = allPeople
.GroupBy(p =& new {p.Id, p.Name} )
.Select(g =& g.First())
.ToList();
&以上,您觉得哪种方案更好一些呢?个人最偏向于第二种用法,您呢?
转载自:/A_ming/archive//3097062.html
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:357497次
积分:3972
积分:3972
排名:第4978名
原创:45篇
转载:173篇
评论:50条
(2)(12)(7)(5)(3)(6)(8)(1)(3)(4)(1)(4)(4)(5)(9)(2)(6)(17)(16)(6)(17)(23)(15)(3)(2)(2)(1)(4)(5)(6)(4)(3)(9)(1)(1)1628人阅读
.NET(201)
& &public class PvComparer : IEqualityComparer&ProductDetailsModel.ProductVariantModel.PvAttributeValueModel&
& & & & & & public bool Equals(ProductDetailsModel.ProductVariantModel.PvAttributeValueModel x, ProductDetailsModel.ProductVariantModel.PvAttributeValueModel y)
& & & & & & {
& & & & & & & & return x.Value.Equals(y.Value);
& & & & & & }
& & & & & & public int GetHashCode(ProductDetailsModel.ProductVariantModel.PvAttributeValueModel obj)
& & & & & & {
& & & & & & & & return 0;
& & & & & & }
&model.SizeVariantModel = model.SizeVariantModel.Distinct(new JuryComparer()).ToList();
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:253622次
积分:4598
积分:4598
排名:第3937名
原创:214篇
转载:131篇
评论:29条
(5)(5)(10)(1)(4)(2)(2)(1)(9)(5)(4)(2)(6)(11)(10)(1)(13)(11)(5)(18)(11)(17)(8)(21)(19)(17)(2)(6)(4)(2)(4)(1)(13)(4)(18)(3)(5)(6)(5)(3)(6)(3)(4)(1)(1)(38)LINQ的Distinct总结-asp.net-电脑编程网LINQ的Distinct总结作者:Lose.zhang 和相关&&LINQ命名空间下的Distinct方法有两个重载,一个是对TSource的Queryable可查询结果集支持的,别一个是只对T的IList,Enumerable结果集支持的
看一下,如果是返回为iqueryable&T&结果集,只能用distinct()默认的方法,
如果是List&T&,就可以根据自己定义好的比较原则,进行字段级的过滤了
例如,可以对Person类,进行ID,与Name的相等来确实整个对象是否与其它实例对象相等:
&public class Person&&& {&&&&&&& public int ID { }&&&&&&& public string Name { }&&&&&&& public string Email { }&&& }&&& public class PersonCompar : System.Collections.Generic.IEqualityComparer&Person&&&& {&&&&&&& public bool Equals(Person x, Person y)&&&&&&& {&&&&&&&&&&& if (x == null)&&&&&&&&&&&&&&& return y ==&&&&&&&&&&& return x.ID == y.ID;&&&&&&& }&&&&&&& public int GetHashCode(Person obj)&&&&&&& {&&&&&&&&&&& if (obj == null)&&&&&&&&&&&&&&& return 0;&&&&&&&&&&& return obj.ID.GetHashCode();&&&&&&& }&&& }
如果一个list&person&的实例为
personList,那么,它根据ID过滤的程序为
&personList.Distinct(new PropertyComparer&Person&("ID")).ToList().ForEach(i =& Console.WriteLine(i.ID + i.Name));
PropertyComparer.cs代码如下
&/// &summary&&&& /// 属性比较器&&& /// &/summary&&&& /// &typeparam name="T"&&/typeparam&&&& public class PropertyComparer&T& : IEqualityComparer&T&&&& {&&&&&&& private PropertyInfo _PropertyI&&&&&&& /// &summary&&&&&&&& /// 通过propertyName 获取PropertyInfo对象&&&&&&& /// &/summary&&&&&&&& /// &param name="propertyName"&&/param&&&&&&&& public PropertyComparer(string propertyName)&&&&&&& {&&&&&&&&&&& _PropertyInfo = typeof(T).GetProperty(propertyName,&&&&&&&&&&& BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public);&&&&&&&&&&& if (_PropertyInfo == null)&&&&&&&&&&& {&&&&&&&&&&&&&&& throw new ArgumentException(string.Format("{0} is not a property of type {1}.",&&&&&&&&&&&&&&&&&&& propertyName, typeof(T)));&&&&&&&&&&& }&&&&&&& }&&&&&&& #region IEqualityComparer&T& Members&&&&&&& public bool Equals(T x, T y)&&&&&&& {&&&&&&&&&&& object xValue = _PropertyInfo.GetValue(x, null);&&&&&&&&&&& object yValue = _PropertyInfo.GetValue(y, null);&&&&&&&&&&& if (xValue == null)&&&&&&&&&&&&&&& return yValue ==&&&&&&&&&&& return xValue.Equals(yValue);&&&&&&& }&&&&&&& public int GetHashCode(T obj)&&&&&&& {&&&&&&&&&&& object propertyValue = _PropertyInfo.GetValue(obj, null);&&&&&&&&&&& if (propertyValue == null)&&&&&&&&&&&&&&& return 0;&&&&&&&&&&& else&&&&&&&&&&&&&&& return propertyValue.GetHashCode();&&&&&&& }&&&&&&& #endregion&&& }相关资料:|||||||LINQ的Distinct总结来源网络,如有侵权请告知,即处理!编程Tags:                &                    }

我要回帖

更多关于 linq distinct 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信