最近项目中在用Linq Distinct想要将重复的资料去除时,发现它跟Any之类的方法有点不太一样,不能很直觉的在呼叫时直接带入重复数据判断的处理逻辑,所以当我们要用某个成员属性做重复数据的判断时,就必需绕一下路,这边稍微将处理的方法做个整理并记录一下。
首先为了方便接下去说明,我们必须先来准备后面会用到的数据类别,这边一样用笔者最常用来示范的Person类别,内含两个成员属性ID与Name。

view source

print?

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过滤掉。
...

view source

print?

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函式来过滤数据。
...

view source

print?

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对象带入。

view source

print?

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类别。

view source

print?

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对象。

view source

print?

1.distinctDatas = datas.Distinct(new PropertyComparer<Person>("Name"));

2.ShowDatas(distinctDatas);

这样的作法是减少了许多额外的负担,但是感觉还是少了一条路,用起来也还是必须要建立Compare对象,而且反射也存在着效能的问题,如果每个元素都透过这个Compare去做判断,感觉处理上也不是很漂亮。所以有人也意识到了这个问题,用扩充方法提供了一条我们比较熟悉的路,可以直接将Lambda带入以决定元素要怎样过滤。

view source

print?

01.public static class EnumerableExtender

02.{

03.public static IEnumerable<TSource> Distinct<TSource, TKey>(thisIEnumerable<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.}

使用上会好写许多。

view source

print?

1.distinctDatas = datas.Distinct(person => person.Name);

2.ShowDatas(distinctDatas);

若是不想加入额外的类别,我们也可以透过Group方式来达到类似的效果。

view source

print?

1.distinctDatas = from data in datas

2.group data by data.Name into g

3.select g.First();

4.ShowDatas(distinctDatas);

Linq使用Distinct删除重复数据时如何指定所要依据的成员属性zz的更多相关文章

  1. Distinct删除重复数据时 自定义的方法比较【转】

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

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

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

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

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

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

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

  5. mongodb删除重复数据

    注:mongodb当前版本是3.4.3   插入六条数据:   查询存在重复的数据:   查询并循环删除重复数据:   删除语句解析: db.userInfo.aggregate([     {   ...

  6. SQL表之间复制数据、选出随机几条数据、删除重复数据、取得自增长列等操作

    --表之间数据复制 SELECT* INTO yozhu FROM yo --复制一份表 SELECT* INTO yozhu1 FROM yo where 1<>1 --只复制表结构,无 ...

  7. SQL server 存储过程 C#调用Windows CMD命令并返回输出结果 Mysql删除重复数据保留最小的id C# 取字符串中间文本 取字符串左边 取字符串右边 C# JSON格式数据高级用法

    create proc insertLog@Title nvarchar(50),@Contents nvarchar(max),@UserId int,@CreateTime datetimeasi ...

  8. mysql删除重复数据,保留最新的那一条

    因为数据库没键外键,在关联查询的时候,会碰到查询条数多余数据库实际条数,这因为关联字段在表中有重复值而导致的. 解决方案: 1.数据库脚本删除重复数据,保留最新的一条 2.对关联字段增加唯一约束 例如 ...

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

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

随机推荐

  1. Lucas的数论(math)

    Lucas的数论(math) 题目描述 去年的今日,Lucas仍然是一个热爱数学的孩子.(现在已经变成业界毒瘤了> <) 在整理以前的试题时,他发现了这么一道题目:求\(\sum\limi ...

  2. JavaScript常用事件

    一般事件 事件 浏览器支持 描述 onClick HTML: 2 | 3 | 3.2 | 4   Browser: IE3 | N2 | O3 鼠标点击事件,多用在某个对象控制的范围内的鼠标点击 on ...

  3. css排版

    先介绍如何设定字体.颜色.大小.段落空白等比较简单的应用,后面再介绍下比如首字下沉.首行缩进.最后讲一些常用的web页面中文排版,比如中文字的截断.固定宽度词内折行(word-wrap和word-br ...

  4. 【转】打造属于自己的Android Studio神器

    本文转载自:http://www.stormzhang.com/android/2015/05/26/android-tools/,并加以修改.黄色底部分是本人添加的内容. 一晃好久没更新博客了,最近 ...

  5. 使用eclipse开发Java web应用

    前面说了手动配置一个应用,手动配置可以更深入的理解web应用的分布,但是一般的编辑器没有语法错误提示,所以开发起来对于错误的寻找不太容易,效率相对较低,所以在理解清楚web项目的结构之后,我们使用ec ...

  6. 什么是网络爬虫(Spider) 程序

    Spider又叫WebCrawler或者Robot,是一个沿着链接漫游Web 文档集合的程序.它一般驻留在服务器上,通过给定的一些URL,利用HTTP等标准协议读取相应文档,然后以文档中包括的所有未访 ...

  7. WMI

    https://wiki.jenkins-ci.org/display/JENKINS/Windows+slaves+fail+to+start+via+DCOM#Windowsslavesfailt ...

  8. 添加Java文档注释

    一.在Eclipse中add javadoc comment的快捷键为: 快捷键为:ALT + SHIFT +J 二.Window-->Preferences-->General--> ...

  9. HTML5中的DOMContentLoaded 和 touchmove

    Html5的出现确实解决了一部分页面交互的问题,同时它的一些特性还是没能被我们掌握,今天主要聊聊Html5中的DomcontenLoaded和touchmove事件的属性和使用: DomcontenL ...

  10. Wcf for wp8 调试Wcf服务程序(四)

    1.要以管理员身份进行登录vs2012 否则会提示: 2.在wcf 服务程序上设为启动项 3.编译 运行你的wcf服务程序 点击 就出现wcftestclient.exe 客户端调试程序 双击点击Re ...