Distinct删除重复数据时 自定义的方法比较【转】
最近项目中在用Linq Distinct想要将重复的资料去除时,发现它跟Any之类的方法有点不太一样,不能很直觉的在呼叫时直接带入重复数据判断的处理逻辑,所以当我们要用某个成员属性做重复数据的判断时,就必需绕一下路,这边稍微将处理的方法做个整理并记录一下。
首先为了方便接下去说明,我们必须先来准备后面会用到的数据类别,这边一样用笔者最常用来示范的Person类别,内含两个成员属性ID与Name。
01.
public
struct
Person
02.
{
03.
#region Property
04.
/// <summary>
05.
/// Gets or sets the ID.
06.
/// </summary>
07.
/// <value>The ID.</value>
08.
public
string
ID {
get
;
set
; }
09.
10.
/// <summary>
11.
/// Gets or sets the name.
12.
/// </summary>
13.
/// <value>The name.</value>
14.
public
string
Name {
get
;
set
; }
15.
#endregion
16.
17.
18.
#region Public Method
19.
/// <summary>
20.
/// Returns a <see cref="System.String"/> that represents this instance.
21.
/// </summary>
22.
/// <returns>
23.
/// A <see cref="System.String"/> that represents this instance.
24.
/// </returns>
25.
public
override
string
ToString()
26.
{
27.
return
Name;
28.
}
29.
#endregion
接着准备要用来测试的资料,这边准备了十一个Person对象,前十个对象的名称都是Larry,第十一个对象的名称为LastLarry。期望后面可以透过Distinct将重复的Larry过滤掉。
...
1.
var datas =
new
List<Person>();
2.
int
idx = 0;
3.
for
(idx = 0; idx < 10; ++idx)
4.
{
5.
datas.Add(
new
Person() {ID = idx.ToString(), Name =
"Larry"
});
6.
}
7.
datas.Add(
new
Person() { ID = idx.ToString(), Name =
"LastLarry"
});
8.
...
若是我们想直接用内建的Distinct函式来过滤数据。
...
01.
var distinctDatas = datas.Distinct();
02.
ShowDatas(distinctDatas);
03.
...
04.
private
static
void
ShowDatas<T>(IEnumerable<T> datas)
05.
{
06.
foreach
(var data
in
datas)
07.
{
08.
Console.WriteLine(data.ToString());
09.
}
10.
}
可以看到运行起来并不如我们所预期的,过滤出来的数据跟没过滤一样。
为了解决这个问题,我们必须要做个可依照Person.Name去做比较的Compare类别,该Compare类别必须实做IEqualityCompare.Equals与IEqualityCompare.GetHashCode方法,并在呼叫Distinct过滤时将该Compare对象带入。
01.
distinctDatas = datas.Distinct(
new
PersonCompare());
02.
ShowDatas(distinctDatas);
03.
...
04.
class
PersonCompare : IEqualityComparer<Person>
05.
{
06.
#region IEqualityComparer<Person> Members
07.
08.
public
bool
Equals(Person x, Person y)
09.
{
10.
return
x.Name.Equals(y.Name);
11.
}
12.
13.
public
int
GetHashCode(Person obj)
14.
{
15.
return
obj.Name.GetHashCode();
16.
}
17.
18.
#endregion
19.
}
运行起来就会是我们所期望的样子。
www.it165.net
但是这样做代表我们每次碰到新的类别就必须要实现对应的Compare类别,用起来十分的不便。因此有人就提出用泛型加上反射的方式做一个共享的Compare类别。
01.
public
class
PropertyComparer<T> : IEqualityComparer<T>
02.
{
03.
private
PropertyInfo _PropertyInfo;
04.
05.
/// <summary>
06.
/// Creates a new instance of PropertyComparer.
07.
/// </summary>
08.
/// <param name="propertyName">The name of the property on type T
09.
/// to perform the comparison on.</param>
10.
public
PropertyComparer(
string
propertyName)
11.
{
12.
//store a reference to the property info object for use during the comparison
13.
_PropertyInfo =
typeof
(T).GetProperty(propertyName,
14.
BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public);
15.
if
(_PropertyInfo ==
null
)
16.
{
17.
throw
new
ArgumentException(
string
.Format(
"{0} is not a property of type {1}."
, propertyName,
typeof
(T)));
18.
}
19.
}
20.
21.
#region IEqualityComparer<T> Members
22.
23.
public
bool
Equals(T x, T y)
24.
{
25.
//get the current value of the comparison property of x and of y
26.
object
xValue = _PropertyInfo.GetValue(x,
null
);
27.
object
yValue = _PropertyInfo.GetValue(y,
null
);
28.
29.
//if the xValue is null then we consider them equal if and only if yValue is null
30.
if
(xValue ==
null
)
31.
return
yValue ==
null
;
32.
33.
//use the default comparer for whatever type the comparison property is.
34.
return
xValue.Equals(yValue);
35.
}
36.
37.
public
int
GetHashCode(T obj)
38.
{
39.
//get the value of the comparison property out of obj
40.
object
propertyValue = _PropertyInfo.GetValue(obj,
null
);
41.
42.
if
(propertyValue ==
null
)
43.
return
0;
44.
45.
else
46.
return
propertyValue.GetHashCode();
47.
}
48.
49.
#endregion
50.
}
使用时只要带入泛型的型态与成原属性的名称,就可以产生出需要的Compare对象。
1.
distinctDatas = datas.Distinct(
new
PropertyComparer<Person>(
"Name"
));
2.
ShowDatas(distinctDatas);
这样的作法是减少了许多额外的负担,但是感觉还是少了一条路,用起来也还是必须要建立Compare对象,而且反射也存在着效能的问题,如果每个元素都透过这个Compare去做判断,感觉处理上也不是很漂亮。所以有人也意识到了这个问题,用扩充方法提供了一条我们比较熟悉的路,可以直接将Lambda带入以决定元素要怎样过滤。
01.
public
static
class
EnumerableExtender
02.
{
03.
public
static
IEnumerable<TSource> Distinct<TSource, TKey>(
this
IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
04.
{
05.
HashSet<TKey> seenKeys =
new
HashSet<TKey>();
06.
foreach
(TSource element
in
source)
07.
{
08.
var elementValue = keySelector(element);
09.
if
(seenKeys.Add(elementValue))
10.
{
11.
yield
return
element;
12.
}
13.
}
14.
}
15.
}
使用上会好写许多。
1.
distinctDatas = datas.Distinct(person => person.Name);
2.
ShowDatas(distinctDatas);
若是不想加入额外的类别,我们也可以透过Group方式来达到类似的效果。
1.
distinctDatas = from data
in
datas
2.
group data by data.Name into g
3.
select g.First();
4.
ShowDatas(distinctDatas);
Distinct删除重复数据时 自定义的方法比较【转】的更多相关文章
- Linq使用Distinct删除重复数据时如何指定所要依据的成员属性zz
最近项目中在用Linq Distinct想要将重复的资料去除时,发现它跟Any之类的方法有点不太一样,不能很直觉的在呼叫时直接带入重复数据判断的处理逻辑,所以当我们要用某个成员属性做重复数据的判断时, ...
- Oracle 删除重复数据的几种方法
去重 第一种:distinct create table tmp_t3 as select distinct * from t3; drop table t3; alter table tmp_t2 ...
- Excel删除重复数据及用公式筛选重复项并标记颜色突出显示
当表格记录比较多时,常常会有重复数据,而重复记录往往只希望保存一条,因此需要把多余的删除:在 Excel 中,删除重复数据有两种方法,一种是用"删除重复数据"删除,另一种是用&qu ...
- orcl数据库查询重复数据及删除重复数据方法
工作中,发现数据库表中有许多重复的数据,而这个时候老板需要统计表中有多少条数据时(不包含重复数据),只想说一句MMP,库中好几十万数据,肿么办,无奈只能自己在网上找语句,最终成功解救,下面是我一个实验 ...
- MySQL中删除重复数据的简单方法,mysql删除重复数据
MYSQL里有五百万数据,但大多是重复的,真实的就180万,于是想怎样把这些重复的数据搞出来,在网上找了一圈,好多是用NOT IN这样的代码,这样效率很低,自己琢磨组合了一下,找到一个高效的处理方式, ...
- oracle中查找和删除重复记录的几种方法总结
平时工作中可能会遇到当试图对库表中的某一列或几列创建唯一索引时,系统提示 ORA-01452 :不能创建唯一索引,发现重复记录. 下面总结一下几种查找和删除重复记录的方法(以表CZ为例): 表CZ的结 ...
- T-SQL技术收集——删除重复数据
原文:T-SQL技术收集--删除重复数据 在工作和面试中,经常出现如何查询或者删除重复数据的问题,如果有主键,那还好办一点,如果没有主键,那就有点麻烦. 当一个表上没有辅助键时,如果使用SSMS界面来 ...
- 【MySQL】测试MySQL表中安全删除重复数据只保留一条的相关方法
第二篇文章测试说明 开发测试中,难免会存在一些重复行数据,因此常常会造成一些测试异常. 下面简单测试mysql表删除重复数据行的相关操作. 主要通过一下三个大标题来测试说明: 02.尝试删除dept_ ...
- 取两个DataTable的交集,删除重复数据
/// <summary> /// 取两个DataTable的交集,删除重复数据 /// </summary> /// <param name="sourceD ...
随机推荐
- Java优化之输出十万以内的质数
(1)未经优化时所耗费的时间: public class PrimeNumber { public static void main(String[] args) { long start = Sys ...
- 【hibernate merge】session1.merge(T entity)方法的含义和update方法的区别
注意: MERGE语句是SQL语句的一种.在SQL Server.Oracle数据库中可用,MySQL.PostgreSQL中不可用. 1>session1.merge(T entity) 合 ...
- hdu 1030 Delta-wave
Delta-wave Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- JavaScript设计模式——单体模式
一:单体模式简介: 是什么:将代码组织为一个逻辑单元,这个单元中的代码通过单一的变量进行访问.只要单体对象存在一份实例,就可以确信自己的所有代码使用的是同样的全局资源. 用途:1.用来划分命名空间,减 ...
- Spring事务解析1-使用介绍
spring的事务控制让我们从复杂的事务处理中得到解脱,是我们再也不需要去处理获得连接,关闭连接,事务提交和回滚等操作,再也不需要在事务相关的方法中处理大量的try..catch...finally代 ...
- HTML5优点
1.标签的改变:<header>, <footer>, <dialog>, <aside>, <figure>, <section&g ...
- 最火的.NET开源项目
综合类 微软企业库 微软官方出品,是为了协助开发商解决企业级应用开发过程中所面临的一系列共性的问题, 如安全(Security).日志(Logging).数据访问(Data Access).配置管理( ...
- ASP.NET MVC3 中整合 NHibernate3.3、Spring.NET2.0 使用AOP执行事务处理
方法1 <object id="ServiceOperation" type="Spring.Aop.Support.SdkRegularExpressionMet ...
- Delphi 2009 泛型容器单元(Generics.Collections)[1]: TList<T>
Delphi 2009 新增了泛型容器单元: Generics.Collections, 同时还有一个 Generics.Defaults 单元做支持. Generics.Collections 包含 ...
- Codeforces Round #347 (Div. 2)
unrating的一场CF A - Complicated GCD #include <bits/stdc++.h> const int N = 1e5 + 5; char a[105], ...