C#黔驴技巧之去重(Distinct)

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

前言

石头 www.10tou.com

关于C#中默认的Distinct方法在什么情况下才能去重,这个就不用我再多讲,针对集合对象去重默认实现将不再满足,于是乎我们需要自定义实现来解决这个问题,接下来我们详细讲解几种常见去重方案,孰好孰歹自行判之。

分组

首先给出我们需要用到的对象,如下:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

接下来我们添加100万条数据到集合中,如下:

var list = new List<Person>();
for (int i = 0; i < 1000000; i++)
{
    list.Add(new Person() { Age = 18, Name = "jeffcky" });
}

接下来我们对年龄和名称进行分组,然后取第一条即可达到去重,如下:

list = list.GroupBy(d => new { d.Age, d.Name })
    .Select(d => d.FirstOrDefault())
    .ToList();

扩展方法(HashSet去重)

我们知道在C#中HashSet对于重复元素会进行过滤筛选,所以我们写下如下扩展方法,遍历集合元素,最后利用HashSet进行过滤达到去重目的,如下:

public static IEnumerable<TSource> Distinct<TSource, TKey>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector)
    {
        var hashSet = new HashSet<TKey>();
        
        foreach (TSource element in source)
        {
            if (hashSet.Add(keySelector(element)))
            {
                yield return element;
            }
        }
    }

最后调用上述扩展方法即可去重,如下:

 list = list.Distinct(d => new { d.Age, d.Name }).ToList();

扩展方法(IEqualityComparer去重)

在实际项目中有很多通过具体实现类实现该接口,通过重写Equals和HashCode比较属性值来达到去重目的,因为对于每一个类都得实现对应比较器,所以并不通用,反而利用上述方式才是最佳,其实我们大可借助该比较接口实现通用解决方案,对于每一个类都得实现一个比较器的原因在于,我们将属性比较放在类该接口内部,如果我们将属性比较放在外围呢,这个时候就达到了通用解决方案,那么我们怎么实现呢,通过委托来实现,实现该接口的本质无非就是比较HashCode,然后通过Equals比较其值,当比较HashCode时,我们强制其值为一个常量(比如0),当重写Equals方法我们调用委托即可,如下:

public static class Extensions
{
    public static IEnumerable<T> Distinct<T>(
        this IEnumerable<T> source, Func<T, T, bool> comparer)
        where T : class
        => source.Distinct(new DynamicEqualityComparer<T>(comparer));

    private sealed class DynamicEqualityComparer<T> : IEqualityComparer<T>
        where T : class
    {
        private readonly Func<T, T, bool> _func;

        public DynamicEqualityComparer(Func<T, T, bool> func)
        {
            _func = func;
        }

        public bool Equals(T x, T y) => _func(x, y);

        public int GetHashCode(T obj) => 0;
    }
}

最终通过指定属性进行比较即可去重,如下:

list = list.Distinct((a, b) => a.Age == b.Age && a.Name == b.Name).ToList();

性能比较

以上3种常见方式我们已经介绍完毕了,当数据量比较小时,我们大可忽略对集合进行各种操作所带来的性能,但是一旦数据量很大时,我们可能需要考虑性能,能节省一点时间或许有必要,于是乎,在上述100万条数据前提下,我们来分析其耗时情况,如下:

var list = new List<Person>();
for (int i = 0; i < 1000000; i++)
{
    list.Add(new Person() { Age = 18, Name = "jeffcky" });
}

var time1 = Time(() =>
{
    list.GroupBy(d => new { d.Age, d.Name })
        .Select(d => d.FirstOrDefault())
        .ToList();
});
Console.WriteLine($"分组耗时:{time1}");

var time2 = Time(() =>
{
    list.Distinct(d => new { d.Age, d.Name }).ToList();
});
Console.WriteLine($"HashSet耗时:{time2}");

var time3 = Time(() =>
{
    list.Distinct((a, b) => a.Age == b.Age && a.Name == b.Name).ToList();
});
Console.WriteLine($"委托耗时:{time3}");


static long Time(Action action)
{
    var stopwatch = new Stopwatch();
    stopwatch.Start();
    action();
    stopwatch.Stop();
    return stopwatch.ElapsedMilliseconds;
}

总结

上述结果耗时大小比较理论应该不会出现逆转的情况,只是多少的问题,数据量较少时理论上差异也很明显,本文对于去重方式只是基于性能角度来分析,还是那句话大部分情况下,我们完全不需要考虑这些问题,不过,作为程序员的我们可能也想写出高性能、高质量的代码吧,有时候多考虑考虑也无妨,对自身有个好的代码质量要求也未尝不可,也还是那句话,孰好孰歹,自行判之。 

C# 数据库查询语句-第4节.过滤数据(1) C# 数据库查询语句-第4节.过滤数据(1) 作者:陈钰桃 撰写时间:2022 4月17日 第4节. 过滤数据(1) Select Distinct子句 SELECT DISTINCT 子句检索指定列列表中的唯一不同值,换句话说,它从结果集中删除列中的复值。DISTINCT 子句将所有 NULL 值视为相同的值 语法如下所示: SELECT DISTINCT column_name1, column_name2 , … FROM table_name; A.DISTINCT一个字段的示例 以下语句返回 阅读详情

相关推荐

C#实现查询时不显示复记录 (附完整源代码)

C#实现查询时不显示复记录 (附完整源代码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 235

dt消除复行,筛选数据

DataView dvInputData = new DataView(dt);        dvInputData.Sort = "colName";        DataTable dtInputData = dvInputData.ToTable();        for (int i = 1; i         {            if (dtInputData.Rows[i

Neo in SAP 1002

ESP32蓝牙广播数据自定义指南:让你的设备更容易被手机发现

本文详细介绍了如何通过自定义ESP32蓝牙广播数据提升设备在手机端的可发现性。从广播数据结构、扫描响应优化到跨平台兼容性设置,提供了全面的技术指南和实战代码示例,帮助开发者解决智能硬件开发中的蓝牙连接难题。

weixin_29172201的博客 258

C#除DataTable复数据的三种方法

业务需求 最近做一个把源数据库的数据批次导出到目标数据库。源数据库是采集程序采集而来的原始数据库,所以需要对其进行一些处理(过滤一些为空,长度太短或太长,非法字符,复数据)然后在进行入库。其中要避免目标库插入c#教程复数据。这复数据可能是源数据库本身就有复数据,还有就是已经插入避免复插入。 过滤自身复数据解决方案 第一种:采用DataView.ToTable()方法 DataView.ToTable 方法 .NET Framework 2.0 其根据现有 DataView 中的行,创建并返回一个

chinaherolts2008的博客 6099

LINQ to SQL学习 之Select/Distinct和Count/Sum/Min/Max/Avg

以下转自YJingLee's Blog: 上一篇讲述了LINQ,顺便说了一下Where操作,这篇开始我们继续说LINQ to SQL语句,目的让大家从语句的角度了解LINQ,LINQ包括LINQ to Objects、LINQ to DataSets、LINQ to SQL、LINQ to Entities、LINQ to XML,但是相对来说LINQ to SQL在我们程序...

weixin_30918415的博客 432

C# List<T> Lambda取某一属性组合为新List(Select),并Distinct

C# Lambda Select Distinct

liangzhuangdongtou的专栏 1502

c#对象集合_C#黔驴技巧Distinct

原标题:C#黔驴技巧(Distinct)关于C#中默认的Distinct方法在什么情况下才能,这个就不用我再多讲,针对集合对象默认实现将不再满足,于是乎我们需要自定义实现来解决这个问题,接下来我们详细讲解几种常见方案,孰好孰歹自行判之。分组首先给出我们需要用到的对象,如下:publicclassPerson{publicstringName { get; set; }public...

weixin_42126668的博客 2531

list_C#黔驴技巧Distinct

关于C#中默认的Distinct方法在什么情况下才能,这个就不用我再多讲,针对集合对象默认实现将不再满足,于是乎我们需要自定义实现来解决这个问题,接下来我们详细讲解几种常见方案,孰好孰歹自行判之。分组首先给出我们需要用到的对象,如下:publicclassPerson{publicstringName{get;set;}publicintA...

weixin_39781143的博客 541

list_C#黔驴技巧Distinct

关于C#中默认的Distinct方法在什么情况下才能,这个就不用我再多讲,针对集合对象默认实现将不再满足,于是乎我们需要自定义实现来解决这个问题,接下来我们详细讲解几种常见方案,孰好孰歹自行判之。分组首先给出我们需要用到的对象,如下:publicclassPerson{publicstringName{get;set;}publicintA...

weixin_29751415的博客 472

C# DataTable复的2种方式

sourceDT是获取到的一个DataTable类型的集合对象 复使用方式: 实例化一个DataView对象为dv,直接dv.ToTable()即可,ToTable中可为(true,“用于判断复的列”), 如图中所示, 需要注意的是此处用于判断的列,几个,在新的表中就出现几个 ...

qq_27929003的博客 5758

C#-DataTable-Distinct

C#中datatable的方法 更新时间:2014年10月12日 11:31:17 投稿:shichen2014 我要评论 这篇文章主要介绍了C#中datatable的方法,通过两种不同的方法对比分析了datatable技巧,非常具有实用价值,需要的朋友可以参考下 本文实例讲述了C#中datatable的方法,分享给大家供大家参考。具体方法如下: 这里主...

cxu123321的博客 1995

c# datatable.select() group by 和 DataTable中进行Distinct、Group by、Join、Create

DataTable dt = new DataTable(); dt.Columns.Add("A"); dt.Columns.Add("B"); dt.Columns.Add("C"); dt.Rows.Add("a1", "b1", "c1"); dt.Rows.Add("a1", "b2", "c2"); dt.Rows.Add

livening的专栏 1万+

C# Distinct方法的使用笔记

C# 3.0开始提供了Distinct方法,这对于

极地语音工作室:专注语音处理、Praat脚本、TextGrid标注、声学分析与相关AI工具实践。 4万+

DataTable 中Distinct操作

DataTable dt = ds.Tables[0]; DataView dataView = dt.DefaultView; DataTable dtDistinct = dataView.ToTable(true, "GC002_UserID", "GC002_UserName","字段3","字段3","字段5");//DataTable根据 UserID...

weixin_30747253的博客 1544

select distinct 语句详解

由以上例子,可以很好的理解 distinct 关键字的作用。

fanfangyu的博客 2298

distinct

1、distinct必须是select 语句中的第一列, select name, distinct(id)是错误的。

编程开发资料库 156

C# 除DataTable表中复行

除DataTable表中复行有两种方法: 一、利用sql语句的distinct 关键字 如:select distinct * from table_name; 二、利用DataView.ToTable()方法 1.DataView.ToTable() 根据现有DataView中的行,创建并返回一个新的DataTable。 2.DataView.ToTable(String) 根据现有DataView中的行,创建并返回一个新的DataTable。参数String为返回的DataTable的名称,输出的表

weixin_41561640的博客 7339

c# list集合根据某个字段_完美解决c# distinct不好用的问题

当一个结合中想根据某一个字段做方法时使用以下代码IQueryable 继承自IEnumerable先举例:#region linq to objectList peopleList = new List();peopleList.Add(new People { UserName = "zzl", Email = "1" });peopleList.Add(new People { UserN...

weixin_39996035的博客 2796

C#

advisercreateList是一个list集合,后面才是关键

weixin_44385858的博客 2016
上一篇: 新书《OpenShift云原生架构:原理与实践》第一章第三节:企业级PaaS平台OpenShift
下一篇: 如何写好、管好单元测试?基于Roslyn+CI分析单元测试,严控产品提测质量
keocce
博客等级 码龄7年 41粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值