C# 中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();
}
可以看到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();
}
}
使用的时候,只需要
var distinctProduct = products.Distinct(new ProductIdComparer());
结果如下:

现在假设我们要 按照 Name来筛选重复呢?
很明显,需要再添加一个类ProductNameComparer.
那能不能使用泛型类呢??
新建类PropertyComparer<T> 继承IEqualityComparer<T> 内容如下:
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
}
主要是重写的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 = 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();
C# 中distinct的使用的更多相关文章
- SQL中distinct的用法
SQL中distinct的用法 1.作用于单列 2.作用于多列 3.COUNT统计 4.distinct必须放在开头 5.其他 在表中,可能会包含重复值.这并不成问题,不过,有时您也许希望仅仅列出 ...
- Thinkphp 中 distinct 的用法
TP中distinct()的用处主要是去除重复的值 在Thinkphp手册中也详细说明了(链接:http://document.thinkphp.cn/manual_3_2.html#distinct ...
- MySQL中distinct和group by性能比较[转]
MySQL中distinct和group by性能比较[转] 之前看了网上的一些测试,感觉不是很准确,今天亲自测试了一番.得出了结论(仅在个人计算机上测试,可能不全面,仅供参考) 测试过程: 准备一张 ...
- SQL中distinct的用法和left join查询的含义
SQL中distinct的用法 1.作用于单列 2.作用于多列 3.COUNT统计 4.distinct必须放在开头 5.其他 在表中,可能会包含重复值.这并不成问题,不过,有时您也许希望仅仅列出 ...
- Thinkphp中distinct的用法
Thinkphp中distincat的用法 TP中distinct()的用处主要是去除重复的值 在Thinkphp手册中也详细说明了(链接:http://document.thinkphp.cn/ma ...
- hive中select中DISTINCT的技巧和使用
hive中select中DISTINCT的技巧和使用 单表的唯一查询用:distinct 多表的唯一查询用:group by 在使用MySQL时,有时需要查询出某个字段不重复的记录,虽然mysql提供 ...
- mysql中distinct的用法
本事例实验用表task,结构如下 MySQL> desc task; +-------------+------------+------+-----+-------------------+- ...
- 扩展lamda表达中distinct按照字段去除重复
首先,我们定义一个Student类来测试. public class Student { public int ID { get; set; } public string Name { get; s ...
- SQL中distinct的用法(转自博主:Rain Man)
在表中,可能会包含重复值.这并不成问题,不过,有时您也许希望仅仅列出不同(distinct)的值.关键词 distinct用于返回唯一不同的值. 表A: 示例1 select distinct nam ...
随机推荐
- Base64封装类
using System;using System.Collections.Generic;using System.Linq;using System.Web; /// <summary> ...
- 常用 C 头文件
ISO C 标准定义的头文件 头文件 说明 <assert.h> 验证程序断言 <complex.h> 复数算术运算支持 <ctype.h> 字符分类和映射支持 & ...
- 第7章 使用RAID与LVM磁盘阵列技术
章节简述: 您好,此章节为新增加的知识内容,正在努力的排版完善,预习2016年9月中旬完成,感谢您的支持,QQ群:340829. 7.1 磁盘冗余阵列 1988年由加利福尼亚大学伯克利分校发表的文章 ...
- why we use Symbols in Hash
Rather than using Strings as the keys in a Hash, it’s better practice to use Symbols. Symbols are ju ...
- Nested List Weight Sum I & II
Nested List Weight Sum I Given a nested list of integers, return the sum of all integers in the list ...
- 获取网页文档的URL和连接来源
<script type="text/javascript">document.write("链接来源:"+document.referrer+&q ...
- 2013 ACM/ICPC 长沙网络赛J题
题意:一个数列,给出这个数列中的某些位置的数,给出所有相邻的三个数字的和,数列头和尾处给出相邻两个数字的和.有若干次询问,每次问某一位置的数字的最大值. 分析:设数列为a1-an.首先通过相邻三个数字 ...
- iOS tableview 选中Cell后的背景颜色和文字颜色
做下记录,备忘 改文字颜色其实是UILabel的属性,改背景颜色是cell的属性,都和tableview无关. cell.textLabel.textColor = BAR_COLOR; cell.t ...
- 通过eclipse配置Spring MVC项目
上一篇刚建立了一个简单的Spring项目,其实Spring MVC是一个和Struts2一样的基于MVC设计模式的web框架,并且继承了MVC的优点,是基于请求驱动的轻量级的web框架,spring ...
- JavaScript设计模式 - 单例模式
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 一.实现一个标准的单例模式,用一个变量来标志当前是否已经为某个类创建过对象, 如果是,则在下一次获取该对象实例时,直接返回之前创建的对 ...