C# LINQ去重

C# 使用自帶的Distinct無法通過某一個屬性值去重,因爲使用自定義擴展方法去重。
Net6版本出來了自帶的DistinctBy屬性。低版本沒有。

擴展代碼

    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;
        }

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

實體類

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

調用

        var list = new List<Person>();

        //第一種方式
        var list1 = list.GroupBy(d => d.Id).Select(d => d.FirstOrDefault()).ToList();

        //第二種方式
        var list2 = list.DistinctBy(d => d.Id).ToList();

        //第三種方式
        var list3 = list.Distinct((a, b) => a.Age == b.Age && a.Name == b.Name).ToList();

性能比較

//數據量小基本沒有性能問題,數據量大建議使用第三種。
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章