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

最近项目中在用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);

时间: 2024-12-17 18:33:14

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

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

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

DISTINCT删除重复数据

DISTINCT 语法 1 SELECT DISTINCT NAME FROM TABLENAME 删除去重SQL语法 DELETE FROM QuestionLib where ID in ( select min(ID) ID FROM QuestionLib group by NAME having Count(0)>1);

数据库删除重复数据

第一,数据库中实体重复的解决方法. 实体重复也就是完全重复:即表中两行记录完全一样的情况.这类数据重复就需要删除一条记录,解决方法比较简单,具体操作如下: 使用select distinct * from tableName就可以得到无重复记录的结果集.如果该表需要删除重复的记录(重复记录保留1条),可以按以下方法删除select distinct * into #Tmp from tableNamedrop table tableNameselect * into tableName from

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

工作中,发现数据库表中有许多重复的数据,而这个时候老板需要统计表中有多少条数据时(不包含重复数据),只想说一句MMP,库中好几十万数据,肿么办,无奈只能自己在网上找语句,最终成功解救,下面是我一个实验,很好理解. ------------------------------------------------------------------------------------------------------------------------ 假设有一张人员信息表cs(姓名,证件号,地址

MySQL 处理重复数据:防止表中出现重复数据、统计、过滤、删除重复数据

MySQL 处理重复数据 有些 MySQL 数据表中可能存在重复的记录,有些情况我们允许重复数据的存在,但有时候我们也需要删除这些重复的数据. 本章节我们将为大家介绍如何防止数据表出现重复数据及如何删除数据表中的重复数据. 防止表中出现重复数据 你可以在 MySQL 数据表中设置指定的字段为 PRIMARY KEY(主键) 或者 UNIQUE(唯一) 索引来保证数据的唯一性. 让我们尝试一个实例:下表中无索引及主键,所以该表允许出现多条重复记录. CREATE TABLE person_tbl

mysql 删除重复数据

如题:mysql 数据库删除重复数据 因为是mysql 所以其他数据哭的命令在mysql 中是不能使用的.不要想当然的使用sql 脚本 delete from table1 where field1 in (select field1 from table1 group by field1 having count(field1) > 1) and rowid not in (select min(rowid) from table1 group by field1 having count(f

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

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 /// <summary>         /// 取两个DataTable的交集,删除重复数据         /// </summary>         /// <param name="sourceDataTable">源DataTable</param>         

mongodb删除重复数据

插入六条数据: 查询存在重复的数据: 查询并循环删除重复数据: 删除语句解析: db.userInfo.aggregate([ { $group: { _id: {userName: '$userName',age: '$age'},count: {$sum: 1},dups: {$addToSet: '$_id'}} }, { $match: {count: {$gt: 1}} } ]).forEach(function(doc){ doc.dups.shift(); db.userInfo.

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

因为数据库没键外键,在关联查询的时候,会碰到查询条数多余数据库实际条数,这因为关联字段在表中有重复值而导致的. 解决方案: 1.数据库脚本删除重复数据,保留最新的一条 2.对关联字段增加唯一约束 例如: 以下表,部门表的部门编号出现了重复. 首先判断是不是重复 1 select count(*) from department d 2 3 select count(*) from ( select distinct dept_code from department ) 看以上查出来的数量是不是