为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 ...
随机推荐
- 百度api的使用
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- 第2章Zabbix基础进阶
p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-bottom: .0001pt; text-align: justify; t ...
- div背景图片或颜色不显示的解决办法
背景图片不显示的原因: 1. css没有被调用 2. css图片地址不对 3. div的高度没有固定,是auto.没有设值或者高度不够 4. div被嵌套 5. div代码不规范 解决办法: (1)D ...
- 老李分享:Uber究竟是用什么开发语言?
poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821478,咨询电话010-845052 ...
- 老李推荐:第5章2节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 启动流程概览
老李推荐:第5章2节<MonkeyRunner源码剖析>Monkey原理分析-启动运行: 启动流程概览 每个应用都会有一个入口方法来供操作系统调用执行,Monkey这个应用的入口方法就 ...
- java调试技能之dubbo调试 ---telnet
dubbo作为一个远程调用框架,虽与同类型的框架,不知道谁优谁劣,但是就公司层面使用来说,还是很棒的.这里简单的写一下怎么使用和调试技巧,就算是作个使用总结吧,供快速使用和问题解决! dubbo是基于 ...
- python_嵌套列表变成普通列表
如何把[1, 5, 6, [2, 7, [3, [4, 5, 6]]]]变成[1, 5, 6, 2, 7, 3, 4, 5, 6]? 思考: -- for循环每次都遍历列表一层 -- 把取出的单个值加 ...
- 不忘初心 --- 重读<<The C Programming Language>>
这篇文章应该发布在好几年前,2011年计算机界大师Dennis Ritchie仙逝,那时对大师的映象还停留在大一刚学编程时:Unix的合作开发者,C语言的发明人.通过网上的纪念文章<<Un ...
- 抽象工厂模式(Abstract Factory)
(二)抽象工厂模式(Abstract Factory) 1.抽象工厂模式(Abstract Factory),提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 2.抽象工厂模式是 ...
- Linux常用命令List
参考<linux命令行大全> 一.文件命令 cd - 切换为之前目录 wc -l -w file cmd --help apropos keyword apropos cpu > t ...