为Distinct准备的通用对比器
使用Linq过滤重复对象的时候,我们使用Distinct。
但是Distinct对int long等值类型才有效果,对于对象我们需要自己写个对象。
以下利用泛型封装了两个类:
CommonComparer<T>
public class CommonComparer<T> : IEqualityComparer<T>
{
Func<T, string> GetStrigPropertyValueFunc;
Func<T, int> GetInt32PropertyValueFunc;
Func<T, long> GetInt64PropertyValueFunc; public CommonComparer(string propertyName)
{
var tType = typeof(T);
PropertyInfo propertyInfo = tType.GetProperty(propertyName); ParameterExpression pExpress = Expression.Parameter(tType);
MemberExpression bodyExpress = Expression.Property(pExpress, propertyInfo); switch (propertyInfo.PropertyType.Name)
{
case "Int32":
GetInt32PropertyValueFunc = Expression.Lambda<Func<T, int>>(bodyExpress, pExpress).Compile();
break;
case "Int64":
GetInt64PropertyValueFunc = Expression.Lambda<Func<T, long>>(bodyExpress, pExpress).Compile();
break;
case "String":
GetStrigPropertyValueFunc = Expression.Lambda<Func<T, string>>(bodyExpress, pExpress).Compile();
break;
default: throw new NotSupportedException("对比器只支持int32、int64、String");
}
} public bool Equals(T x, T y)
{
if (GetStrigPropertyValueFunc != null)
{
var xValue = GetStrigPropertyValueFunc(x);
var yValue = GetStrigPropertyValueFunc(y); if (xValue == null) return yValue == null;
return xValue.Equals(yValue);
}
else if (GetInt32PropertyValueFunc != null)
{
var xValue = GetInt32PropertyValueFunc(x);
var yValue = GetInt32PropertyValueFunc(y); if (xValue == null) return yValue == null;
return xValue.Equals(yValue);
}
else if (GetInt64PropertyValueFunc != null)
{
var xValue = GetInt64PropertyValueFunc(x);
var yValue = GetInt64PropertyValueFunc(y); if (xValue == null) return yValue == null;
return xValue.Equals(yValue);
} throw new NotSupportedException("没找到支持的委托类型");
} public int GetHashCode(T obj)
{
if (GetStrigPropertyValueFunc != null)
{
var value = GetStrigPropertyValueFunc(obj);
if (obj == null) return 0; return value.GetHashCode();
}
else if (GetInt32PropertyValueFunc != null)
{
var value = GetInt32PropertyValueFunc(obj);
if (obj == null) return 0; return value.GetHashCode();
}
else if (GetInt64PropertyValueFunc != null)
{
var value = GetInt64PropertyValueFunc(obj);
if (obj == null) return 0; return value.GetHashCode();
} return 0;
}
}
ReflectCommonComparer<T>
public class ReflectCommonComparer<T> : IEqualityComparer<T>
{
string PropertyName; public ReflectCommonComparer(string propertyName)
{
PropertyName = propertyName;
} object GetPropertyValue(T x)
{
PropertyInfo propertyInfo = typeof(T).GetProperty(PropertyName);
return propertyInfo.GetValue(x);
} public bool Equals(T x, T y)
{
var xValue = GetPropertyValue(x);
var yValue = GetPropertyValue(y); if (xValue == null) return yValue == null;
return xValue.Equals(yValue);
} public int GetHashCode(T obj)
{
var value = GetPropertyValue(obj);
if (obj == null) return 0; return value.GetHashCode();
}
}
CommonComparer利用的是表达式树来实现的,ReflectCommonComparer是利用反射来实现的。网络上说利用的是表达式树来实现比反射更快。
我做了简单的时间测试,以下是截图:

1000次循环对比,反射更快呀

十万次对比,也是反射的比较快呀。
有可能是我写的表达式树有问题。 有空再去试试。
---
我把去重的数据量变多了之后的对比:

十万次,表达式树更快了。
我的结论是,去重的数据量多的话就用表达式树,少的话就用反射。大概超过80就需要用表达式树了。
因此以上还可以进一步分装。
public static class LinqExtension
{
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source, string propertyName)
{
if (source.Count() > 80)
return source.Distinct(new CommonComparer<T>(propertyName));
else
return source.Distinct(new ReflectCommonComparer<T>(propertyName));
}
}
使用
var newList = list.Distinct("id").ToList(); // id是要用来判断去重的唯一值
为Distinct准备的通用对比器的更多相关文章
- python 通用装饰器,带有参数的装饰器,
# 使用装饰器对有返回值的函数进行装饰# def func(functionName): # print('---func-1----') # def func_in(): # print(" ...
- 通用采集器Modbus协议应用
1. 功能码 通用采集器一般包含DI,DO,AI相关接口,对此类接口主要应用功能码01~06. 3类接口具体对应关系如下: 继电器定义,功能码01/05(01:读线圈,05写线圈) 序号 ...
- Atitit..状态机与词法分析 通用分词器 分词引擎的设计与实现 attilax总结
Atitit..状态机与词法分析 通用分词器 分词引擎的设计与实现 attilax总结 1. 状态机 理论参考1 2. 词法分析理论1 3. 词法分析实例2 4. ---code fsm 状态机通用 ...
- 新闻网页通用抽取器GNEv0.04版更新,支持提取正文图片与源代码
GeneralNewsExtractor以下简称GNE是一个新闻网页通用抽取器,能够在不指定任何抽取规则的情况下,把新闻网站的正文提取出来. 我们来看一下它的基本使用方法. 安装 GNE 使用 pip ...
- MySQL 里面的Where 和Having和Count 和distinct和Group By对比
mysql> select accid as uid,date(datetime) AS datetime from game.logLogin GROUP BY accid HAVING da ...
- Scut:通用配置管理器
1. 配置节 ConfigSection private List<ConfigNode> _configNodes; public class ConfigNode { public C ...
- 面向切面编程AOP,一些通用装饰器
1.一些装饰器,可以减少重复编写.比较常用的. 用的时候函数上面加上装饰器就可以.这是一些装饰器,加在函数或者方法上,减少了很多重复代码. 除此之外工作中也用一些mixin类大幅减少代码. impor ...
- python 通用 修饰器
import functools def log(option): def dec(func): def swapper(*arg, **karg): functools.update_wrapper ...
- 【C#】基础之数组排序,对象大小比较(对比器)
C#基础之数组排序,对象大小比较 原文链接:[OutOfMemory.CN] 从个小例子开始: 1 2 3 int[] intArray = new int[]{2,3,6,1,4,5}; Array ...
随机推荐
- windows32位安装MYSQL-python1.2.3
建议不要用pip安装MYSQL-python,因为会自动选择MYSQL-python1.2.5这个版本,但是这个版本不支持windows 32位系统. 1.首先安装VS2008,因为要依赖VC9.0编 ...
- ruby安装sass报错解决办法
ERROR: Could not find a valid gem 'sass' (>= 0), here is why: Unable to download data from http:/ ...
- 使用Docker容器来源码编译etcd
背景 etcd是CoreOS公司开发的分布式键值对存储库.在Kubernetes中,我们需要使用etcd作为所有REST API对象的持久化存储. 不幸的是,在github的release中,Core ...
- centos6.5 源码安装 gtk 环境
解决 No package 'gtk+-2.0′ found问题方法:yum install libgnomeui-devel 执行了上面的,下面的就可以放弃了,yum 大法好 首先 yum 安装下面 ...
- 为什么要学Python
人生苦短,我用python.在大学四年的本科学习中,Python是我接触过语法最简单,功能最为强大的语言,拥有众多第三方库的支持的语言.如果要选一门编程语言作为入门,建议使用Python.但是为了更加 ...
- Docker系列一之基础快速入门企业实战
1.1什么是LXC LXC为Linux Container的简写.Linux Container容器是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚 ...
- 【原创】Octovis在Ubuntu16.04下运行出现core dump的解决方案
本人SLAM研究新手,使用系统为Ubuntu16.04.本文原址:http://www.cnblogs.com/hitlrk/p/6667253.html 在学习SLAM的过程中,使用Octomap进 ...
- JavaScript写一个表格排序类
依稀记得那是上个星期六的下午,我参加了网易暑期实习生招聘笔试.考得相当糟糕,编程题3个题通过了2个,简答题没做对,选择题貌似是20个题猜了6-7个,99%是挂了,唉唉唉!生活不只眼前的苟且,学习的脚步 ...
- AVL树的旋转操作详解
[0]README 0.0) 本文部分idea 转自:http://blog.csdn.net/collonn/article/details/20128205 0.1) 本文仅针对性地分析AVL树的 ...
- JSP带有属性的自定义标签
新建HelloWelTag类 如何添加jsp-api.jar包 HelloWelTag类详细代码```package bid.zhazhapan.fims.tag;import java.io.IOE ...