• Linq Distinct扩展


    前言

    问题描述:Person类有两个属性ID(int)、Name(string)属性。筛选序列中不重复的Person。

       1: public class Person
       2: {
       3:     public int ID { get; set; }
       4:     public string Name { get; set; }
       5: }

    好吧,看样子得用Distinct方法。不过Distinct方法有两个重载。

       1: public static IEnumerable<TSource> Distinct<TSource>(
       2:     this IEnumerable<TSource> source
       3: )
       4:  
       5: public static IEnumerable<TSource> Distinct<TSource>(
       6:     this IEnumerable<TSource> source,
       7:     IEqualityComparer<TSource> comparer
       8: )

    看样子已经够用了。不过如果我想只按ID唯一,或者按Name唯一呢?派生IEqualityComparer倒是可以解决。不过那也忒坑爹了。还是自己试着写一个扩展吧。

    Distinct扩展

    版本1

    参考封装的Distinct的方法先写一个。声明一个List<TSource>,循环的时候比较,如果不同就加进去。

       1: public static IEnumerable<TSource> Distinct<TSource, TProperty>(this IEnumerable<TSource> source, Func<TSource, TProperty> selector)
       2: {
       3:     if (source == null) throw new ArgumentNullException("source");
       4:     if (selector == null) throw new ArgumentNullException("selector");
       5:     List<TSource> temp = new List<TSource>();
       6:     foreach (var item in source)
       7:     {
       8:         if (temp.Any(t => selector(t).Equals(selector(item))))
       9:         {
      10:             continue;
      11:         }
      12:         temp.Add(item);
      13:     }
      14:     return temp;
      15: }

    测试一下,没什么问题。不过在函数里声明List<TSource>感觉怪怪的,想办法换种方式。

       1: List<Person> list = new List<Person>() 
       2: {
       3:     new Person() { ID = 1, Name = "Alen1" },
       4:     new Person() { ID = 1, Name = "Alen2" },
       5:     new Person() { ID = 2, Name = "Alen2" },
       6:     new Person() { ID = 2, Name = "Alen1" }
       7: };
       8:  
       9: var temp = list.Distinct(t => t.ID);

    版本2

    取指定属性的唯一序列,在循环的时候使用yield返回。

       1: public static IEnumerable<TSource> Distinct<TSource, TProperty>(this IEnumerable<TSource> source, Func<TSource, TProperty> selector)
       2: {
       3:     if (source == null) throw new ArgumentNullException("source");
       4:     if (selector == null) throw new ArgumentNullException("selector");
       5:  
       6:     var pdis = source.Select(t => selector(t)).Distinct();
       7:     foreach (var item in pdis)
       8:     {
       9:         yield return source.First(t => selector(t).Equals(item));
      10:     }
      11: }

    测试通过。

    用Stopwatch分别测试两个函数循环不同次数的时间。对比一下,循环次数在10,000次以上时,版本2耗时大概是版本1的1/40,性能差距算是比较大。

    后记

    目前来说已经够用了,如果还有其他需求,再根据情况扩展吧。

       1: list.Distinct(t => t.ID);
       2: list.Distinct(t => new { t.ID, t.Name }); //根据ID及Name的值分别比较来取唯一,并非比较引用
    知识共享许可协议
    本文彭旭 创作,采用 知识共享 署名-相同方式共享 3.0 中国大陆 许可协议进行许可。欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
  • 相关阅读:
    linux-01-04(创建文件夹mkdir,进入目录命令cd,创建文件命令 echo cp vim touch等,批量创建文件操作)
    linux-05(tar命令的使用)
    linux-06(移动命令mv)
    linux-07(复制命令cp)
    linux-08(查看命令历史记录history)
    cookie
    vue-router路由懒加载
    setTimeout async promise执行顺序总结
    forEach陷阱
    函数节流与函数防抖之间的区别
  • 原文地址:https://www.cnblogs.com/ainijiutian/p/2815007.html
Copyright © 2020-2023  润新知