Различный список объектов на основе произвольного ключа в LINQ - PullRequest
12 голосов
/ 13 апреля 2009

У меня есть несколько объектов:

class Foo {
    public Guid id;
    public string description;
}

var list = new List<Foo>();
list.Add(new Foo() { id = Guid.Empty, description = "empty" });
list.Add(new Foo() { id = Guid.Empty, description = "empty" });
list.Add(new Foo() { id = Guid.NewGuid(), description = "notempty" });
list.Add(new Foo() { id = Guid.NewGuid(), description = "notempty2" });

Я хотел бы обработать этот список таким образом, чтобы поле id было уникальным, и отбросить неуникальные объекты (основываясь на id).

Лучшее, что я мог придумать, это:

list = list.GroupBy(i => i.id).Select(g=>g.First()).ToList();

Есть ли лучший / лучший / более быстрый способ достижения того же результата.

Ответы [ 5 ]

22 голосов
/ 13 апреля 2009

Очень элегантный вариант, позволяющий определить намерение, - определить новый метод расширения в IEnumerable

Итак, у вас есть:

list = list.Distinct(foo => foo.id).ToList();

И ...

    public static IEnumerable<T> Distinct<T,TKey>(this IEnumerable<T> list, Func<T,TKey> lookup) where TKey : struct {
        return list.Distinct(new StructEqualityComparer<T, TKey>(lookup));
    }


    class StructEqualityComparer<T,TKey> : IEqualityComparer<T> where TKey : struct {

        Func<T, TKey> lookup;

        public StructEqualityComparer(Func<T, TKey> lookup) {
            this.lookup = lookup;
        }

        public bool Equals(T x, T y) {
            return lookup(x).Equals(lookup(y));
        }

        public int GetHashCode(T obj) {
            return lookup(obj).GetHashCode();
        }
    }

Подобный вспомогательный класс может быть построен для сравнения объектов. (Это должно будет сделать лучшую обработку нуля)

15 голосов
/ 13 апреля 2009

Использование метода Distinct() примерно в 4 раза быстрее, чем использование GroupBy () в моих неформальных тестах. Для одного миллиона Foo мой тест имеет Distinct () примерно за 0,89 секунды, чтобы создать уникальный массив из неуникального массива, где GroupBy () занимает около 3,4 секунды.

Мой вызов Distinct () выглядит так,

var unique = list.Distinct(FooComparer.Instance).ToArray();

и FooComparer выглядит,

class FooComparer : IEqualityComparer<Foo> {
    public static readonly FooComparer Instance = new FooComparer();

    public bool Equals(Foo x, Foo y) {
        return x.id.Equals(y.id);
    }

    public int GetHashCode(Foo obj) {
        return obj.id.GetHashCode();
    }
}

и моя GroupBy() версия выглядит,

var unique = (from l in list group l by l.id into g select g.First()).ToArray();
1 голос
/ 28 января 2017

Переопределить Равно (объект obj) и GetHashCode () методы:

class Foo
{
    public readonly Guid id;
    public string description;

    public override bool Equals(object obj)
    {
        return ((Foo)obj).id == id;
    }
    public override int GetHashCode()
    {
        return id.GetHashCode();
    }
}

, а затем просто позвоните Distinct () :

list = list.Distinct().ToList();
1 голос
/ 13 апреля 2009
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var list = new List<Foo>();
            list.Add(new Foo() { id = Guid.Empty, description = "empty" });
            list.Add(new Foo() { id = Guid.Empty, description = "empty" });
            list.Add(new Foo() { id = Guid.NewGuid(), description = "notempty" });
            list.Add(new Foo() { id = Guid.NewGuid(), description = "notempty2" });

            var unique = from l in list
                         group l by new { l.id, l.description } into g
                         select g.Key;
            foreach (var f in unique)
                Console.WriteLine("ID={0} Description={1}", f.id,f.description);
            Console.ReadKey(); 
        }
    }

    class Foo
    {
        public Guid id;
        public string description;
    }
}
1 голос
/ 13 апреля 2009

Создайте IEqualityComparer<Foo>, который возвращает true, если поля идентификатора совпадают, и передайте его оператору Distinct ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...