为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 ...
随机推荐
- js的基本介绍
一:JavaScript简称js 他是个脚本语言,需要有宿主文件,他的宿主文件是html文件. 二:js的用法 js :1)进行数据运算 2) 控制浏览器的一些功能 3)控制元素 +元素 +样式 +内 ...
- codeforces 372E. Drawing Circles is Fun
tags:[圆の反演][乘法原理][尺取法]题解:圆の反演:将过O点的圆,映射成不过O的直线,相切的圆反演出来的直线平行.我们将集合S中的点做反演变换:(x,y)->(x/(x^2+y^2), ...
- js数组的几个练习题
第一次在博客园写文章,之前一直自己做记录.现在前端工作两年了,对前端整体技术有较清晰的了解.项目用了vue,react之类的写,如今打算从基础开始,慢慢深入了解原生的JS.这几天清明节,玩的嗨皮,最后 ...
- struts2自定义日期类型转换器
在java web表单中提交的数据难免会有日期类型,struts2支持的日期类型是yyyy-MM-dd,如果是其他格式,就需要自己进行转换.比如yy-MM-dd 要完成自己定义的转换需要完成. 主要的 ...
- Weex的环境搭建以及集成到Android项目
最近由于公司的需要,初步研究了Weex,Weex是阿里开发的一个web的框架,官方的介绍如下: Weex 是一套简单易用的跨平台开发方案,能以 web 的开发体验构建高性能.可扩展的 native 应 ...
- Xcode新建python项目
1.找到电脑上安装Python的路径.OSX系统默认安装了python,默认的路径为/usr/bin/python.不确定的情况下,也可以打开命令行,用 whereis python 命令查看 2.打 ...
- CSAcademy Beta Round #5 Force Graph
题目链接:https://csacademy.com/contest/arhiva/#task/force_graph/ 大意是有若干个节点,每个节点对应一个二维坐标,节点之间相互有斥力存在.同时有些 ...
- MAC Mysql 重置密码
使用mac电脑,当mysql登录密码忘记时,需要重置密码.步骤如下: 1. 关闭当前正在运行的mysql进程. A.进入"偏好设置",选择mysql, 再选"stop m ...
- yum仓库
1.概念: Yum仓库则是为进一步简化RPM管理软件难度而设计的,Yum能够根据用户的要求分析出所需软件包及其相关依赖关系,自动从服务器下载软件包并安装到系统 yum的工作原理:执行yum命令――&g ...
- javaWeb项目(SSH框架+AJAX+百度地图API+Oracle数据库+MyEclipse+Tomcat)之二 基础Hibernate框架搭建篇
我们在搭建完Struts框架之后,从前台想后端传送数据就显得非常简单了.Struts的功能不仅仅是一个拦截器,这只是它的核心功能,此外我们也可以自定义拦截器,和通过注解的方式来更加的简化代码. 接下来 ...