最近项目中在用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 { getset; }
09. 
10./// <summary>
11./// Gets or sets the name.
12./// </summary>
13./// <value>The name.</value>
14.public string Name { getset; }
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删除重复数据时 自定义的方法比较【转】的更多相关文章

  1. Linq使用Distinct删除重复数据时如何指定所要依据的成员属性zz

    最近项目中在用Linq Distinct想要将重复的资料去除时,发现它跟Any之类的方法有点不太一样,不能很直觉的在呼叫时直接带入重复数据判断的处理逻辑,所以当我们要用某个成员属性做重复数据的判断时, ...

  2. Oracle 删除重复数据的几种方法

    去重 第一种:distinct create table tmp_t3 as select distinct * from t3; drop table t3; alter table tmp_t2 ...

  3. Excel删除重复数据及用公式筛选重复项并标记颜色突出显示

    当表格记录比较多时,常常会有重复数据,而重复记录往往只希望保存一条,因此需要把多余的删除:在 Excel 中,删除重复数据有两种方法,一种是用"删除重复数据"删除,另一种是用&qu ...

  4. orcl数据库查询重复数据及删除重复数据方法

    工作中,发现数据库表中有许多重复的数据,而这个时候老板需要统计表中有多少条数据时(不包含重复数据),只想说一句MMP,库中好几十万数据,肿么办,无奈只能自己在网上找语句,最终成功解救,下面是我一个实验 ...

  5. MySQL中删除重复数据的简单方法,mysql删除重复数据

    MYSQL里有五百万数据,但大多是重复的,真实的就180万,于是想怎样把这些重复的数据搞出来,在网上找了一圈,好多是用NOT IN这样的代码,这样效率很低,自己琢磨组合了一下,找到一个高效的处理方式, ...

  6. oracle中查找和删除重复记录的几种方法总结

    平时工作中可能会遇到当试图对库表中的某一列或几列创建唯一索引时,系统提示 ORA-01452 :不能创建唯一索引,发现重复记录. 下面总结一下几种查找和删除重复记录的方法(以表CZ为例): 表CZ的结 ...

  7. T-SQL技术收集——删除重复数据

    原文:T-SQL技术收集--删除重复数据 在工作和面试中,经常出现如何查询或者删除重复数据的问题,如果有主键,那还好办一点,如果没有主键,那就有点麻烦. 当一个表上没有辅助键时,如果使用SSMS界面来 ...

  8. 【MySQL】测试MySQL表中安全删除重复数据只保留一条的相关方法

    第二篇文章测试说明 开发测试中,难免会存在一些重复行数据,因此常常会造成一些测试异常. 下面简单测试mysql表删除重复数据行的相关操作. 主要通过一下三个大标题来测试说明: 02.尝试删除dept_ ...

  9. 取两个DataTable的交集,删除重复数据

    /// <summary> /// 取两个DataTable的交集,删除重复数据 /// </summary> /// <param name="sourceD ...

随机推荐

  1. 基于XMPP协议的Android即时通信系

    以前做过一个基于XMPP协议的聊天社交软件,总结了一下.发出来. 设计基于开源的XMPP即时通信协议,采用C/S体系结构,通过GPRS无线网络用TCP协议连接到服务器,以架设开源的Openfn'e服务 ...

  2. Java可变参数讲解

    如果实现的多个方法,这些方法里面逻辑基本相同,唯一不同的是传递的参数的个数,可以使用可变参数可变参数的定义方法 数据类型...数组的名称,这个数组存储传递过来的参数,类似JavaScript注意点:  ...

  3. Android常用控件之GridView与ExpandableListView的用法

    概述 1.GridView:与ListView相比,可以显示多列,xml布局时其属性numColumns可以设置显示的列数. 2.ExpandableListView:与ListView相比,可以让每 ...

  4. Android开发之ViewPager+ActionBar+Fragment实现响应式可滑动Tab

     今天我们要实现的这个效果呢,在Android的应用中十分地常见,我们可以看到下面两张图,无论是系统内置的联系人应用,还是AnyView的阅读器应用,我们总能找到这样的影子,当我们滑动屏幕时,Tab可 ...

  5. kylin cube测试时,报错:org.apache.hadoop.security.AccessControlException: Permission denied: user=root, access=WRITE, inode="/user":hdfs:supergroup:drwxr-xr-x

    异常: org.apache.hadoop.security.AccessControlException: Permission denied: user=root, access=WRITE, i ...

  6. hdu 1030 Delta-wave

    Delta-wave Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total ...

  7. 如何在Crystal Portlet中正确返回JSON数据给AJAX请求?

    当Crystal Portlet中需要采用Ajax请求,并让后台返回Json数据时,如何才能正确.方便的返回Json数据呢? 以下两种方法均可: 方法一:Ajax请求时,采用RenderURL,对应P ...

  8. WebGL框架 -- three.js

    http://segmentfault.com/a/1190000002421007 http://www.cnblogs.com/shawn-xie/archive/2012/08/16/26425 ...

  9. 把所有css放到一个css文件的格式

    @charset "utf-8"; @import url("global.css"); @import url("common.css") ...

  10. BZOJ 3282 Tree ——KD-Tree

    [题目分析] 明显的LCT维护连通性的题目. access的操作是比较巧妙的,可以把结点到根变成偏爱路径,而且保证了该点是链上深度最深的点. 而且需边的思想也很巧妙,保证了复杂度. 但是只能用于修改路 ...