Linq的Distinct太不给力了[转]
假设我们有一个类:Product
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
}
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();
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
可以看到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 == null;
return x.Id == y.Id;
} public int GetHashCode(Product obj)
{
if (obj == null)
return 0;
return obj.Id.GetHashCode();
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
使用的时候,只需要
var distinctProduct = products.Distinct(new ProductIdComparer());
结果如下:
现在假设我们要 按照 Name来筛选重复呢?
很明显,需要再添加一个类ProductNameComparer.
那能不能使用泛型类呢??
新建类PropertyComparer<T> 继承IEqualityComparer<T> 内容如下:
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
public class PropertyComparer<T> : IEqualityComparer<T>
{
private PropertyInfo _PropertyInfo; /// <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 == null; 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
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
主要是重写的Equals 和GetHashCode 使用了属性的值比较。
使用的时候,只需要:
//var distinctProduct = products.Distinct(new PropertyComparer<Product>("Id"));
var distinctProduct = products.Distinct(new PropertyComparer<Product>("Name"));
结果如下:
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
为什么微软不提供PropertyEquality<T> 这个类呢?
按照上面的逻辑,这个类应该没有很复杂啊,细心的同学可以发现PropertyEquality 大量的使用了反射。每次获取属性的值的时候,都在调用
_PropertyInfo.GetValue(x, null);
可想而知,如果要筛选的记录非常多的话,那么性能无疑会受到影响。
为了提升性能,可以使用表达式树将反射调用改为委托调用,
具体代码如下:
public class FastPropertyComparer<T> : IEqualityComparer<T>
{
private Func<T, Object> getPropertyValueFunc = null; /// <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 == null; 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();
Linq的Distinct太不给力了[转]的更多相关文章
- Linq的Distinct方法的扩展
原文地址:如何很好的使用Linq的Distinct方法 Person1: Id=1, Name="Test1" Person2: Id=1, Name="Test1&qu ...
- Core源码(二) Linq的Distinct扩展
先贴源码地址 https://github.com/dotnet/corefx/tree/master/src/System.Linq/src .NET CORE很大一个好处就是代码的开源,你可以详细 ...
- Linq使用Distinct删除重复数据时如何指定所要依据的成员属性zz
最近项目中在用Linq Distinct想要将重复的资料去除时,发现它跟Any之类的方法有点不太一样,不能很直觉的在呼叫时直接带入重复数据判断的处理逻辑,所以当我们要用某个成员属性做重复数据的判断时, ...
- Linq之Distinct详解
前天在做批量数据导入新增时,要对数据进行有效性判断,其中还要去除重复,如果没出现linq的话可能会新声明一个临时对象集合,然后遍历原始数据判断把符合条件的数据添加到临时集合中,这在有了linq之后显得 ...
- Linq Enumerable.Distinct方法去重
Enumerable.Distinct 方法 是常用的LINQ扩展方法,属于System.Linq的Enumerable方法,可用于去除数组.集合中的重复元素,还可以自定义去重的规则. 有两个重载方法 ...
- linq 之 Distinct的使用
public class Product { public string Name { get;set;} public int Code { get; set; } } class ProductC ...
- 如何很好的使用Linq的Distinct方法
Person1: Id=1, Name="Test1" Person2: Id=1, Name="Test1" Person3: Id=2, Name=&quo ...
- 扩展Linq的Distinct方法动态根据条件进行筛选
声明为了方便自己查看所以引用 原文地址:http://www.cnblogs.com/A_ming/archive/2013/05/24/3097062.html Person1: Id=1, Nam ...
- Linq 用得太随意导致的性能问题一则
问题场景 有一个很多条数据的数据库(数据源),在其中找出指定的项,这些项的 ID 位于 给定的列表中,如 TargetList 中. private readonly IDictionary<s ...
随机推荐
- 光谱郑匡移动互联网O2O完美融合
移动互联网尽管市场颇大,前景广阔,可是由于数据过于密集,非常难精准的定位所谓的目标客户群,然而O2O的线下市场却与互联网市场有极大的反差.一直认为高校周边的小商家是最幸福的生意人,客户明白(就是本校学 ...
- 设计模式 - Abstract Factory模式(abstract factory pattern) 详细说明
Abstract Factory模式(abstract factory pattern) 详细说明 本文地址: http://blog.csdn.net/caroline_wendy/article/ ...
- define a class for a linked list and write a method to delete the nth node.
1.问题 define a class for a linked list and write a method to delete the nth node. 2.算法 template <t ...
- WPF技术触屏上的应用系列(三): 视频播放器的使用及视频播放、播放、暂停、可拖动播放进度效果实现
原文:WPF技术触屏上的应用系列(三): 视频播放器的使用及视频播放.播放.暂停.可拖动播放进度效果实现 去年某客户单位要做个大屏触屏应用,要对档案资源进行展示之用.客户端是Window7操作系统,5 ...
- [渣译文] SignalR 2.0 系列: 支持的平台
原文:[渣译文] SignalR 2.0 系列: 支持的平台 英文渣水平,大伙凑合着看吧,并不是逐字翻译的…… 这是微软官方SignalR 2.0教程Getting Started with ASP. ...
- nyoj 题号12 水厂(两)——南阳oj
标题信息: 喷水装置(二) 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描写叙述 有一块草坪.横向长w,纵向长为h,在它的橫向中心线上不同位置处装有n(n<=1000 ...
- 信息二战炸弹:中国到美国咨询公司Say no
疯抢/文 在禁止Windows8操作系统參与政府採购,以及在中国销售的全部外国IT产品和服务都须通过新的安全审查之后,英国<金融时报>今天报料中国已禁止国企使用美国咨询公司服务. 这则消息 ...
- 开源Math.NET基础数学类库使用(07)一些常用的数学物理常数
原文:[原创]开源Math.NET基础数学类库使用(07)一些常用的数学物理常数 本博客所有文章分类的总目录:http://www.cnblogs.com/asxinyu/ ...
- 接近带给你AngularJS - 经验说明示例
接近带给你AngularJS列: 带你走近AngularJS - 基本功能介绍 带你走近AngularJS - 体验指令实例 带你走近AngularJS - 创建自己定义指令 ------------ ...
- HDU 4513 哥几个系列故事——形成完善II manacher求最长回文
标题来源:哥几个系列故事--形成完善II 意甲冠军:中国 思维:在manacher断 保证非严格递减即可了 #include <cstdio> #include <cstring&g ...