ILookup ( Поиск )<TKey, TVal=""> против.Игрогруппирование<TKey, TVal="">

StackOverflow https://stackoverflow.com/questions/1337539

Вопрос

У меня возникли проблемы с формулированием различий между ILookup<TKey, TVal> и IGrouping<TKey, TVal>, и мне любопытно, правильно ли я это понимаю сейчас.LINQ усугубил проблему, создав последовательности IGrouping предметы, в то же время давая мне ToLookup метод расширения.Так что мне казалось, что они одинаковые, пока я не присмотрелся повнимательнее.

var q1 = 
    from n in N
    group n by n.MyKey into g
    select g;
// q1 is IEnumerable<IGrouping<TKey, TVal>>

Что эквивалентно:

var q2 = N.GroupBy(n => n.MyKey, n => n);
// q2 is IEnumerable<IGrouping<TKey, TVal>>

Который очень похож:

var q3 = N.ToLookup(n => n.MyKey, n => n);
// q3 is ILookup<TKey, TVal>

Прав ли я в следующих аналогиях?

  1. Ан IGrouping<TKey, TVal> является единой группой (т. е.ключевая последовательность), аналогичная KeyValuePair<TKey, TVal> где значение на самом деле представляет собой последовательность элементов (а не один элемент)
  2. Ан IEnumerable<IGrouping<TKey, TVal>> является последовательностью из них (аналогично тому, что вы получаете при повторении IDictionary<TKey, TVal>
  3. Ан ILookup<TKey, TVal> это больше похоже на IDictionary<TKey, TVal> где значение на самом деле представляет собой последовательность элементов
Это было полезно?

Решение

Да, все это верно.

И ILookup<TKey, TValue> также распространяется IEnumerable<IGrouping<TKey, TValue>> поэтому вы можете перебирать все пары ключ/коллекция, а также (или вместо этого) просто искать определенные ключи.

Я в основном думаю о ILookup<TKey,TValue> как будто IDictionary<TKey, IEnumerable<TValue>>.

Имейте в виду, что ToLookup — это операция «сделай это сейчас» (немедленное выполнение), тогда как GroupBy откладывается.Так получилось, что из-за того, как работает «pull LINQ», когда вы начинаете тянуть IGroupings в результате GroupBy, он в любом случае должен прочитать все данные (поскольку вы не можете переключить группу на полпути), тогда как в других реализациях он может выдавать потоковый результат.(Это происходит в Push LINQ;Я ожидаю, что LINQ to Events будет таким же.)

Другие советы

Есть еще одно важное различие между ILookup и IDictionary:первый обеспечивает неизменность в том смысле, что здесь нет методов изменения данных (за исключением случаев, когда потребитель выполняет явное приведение типов).Напротив, в IDictionary есть такие методы, как «Добавить», которые позволяют изменять данные.Итак, с точки зрения функционального и/или параллельного программирования ILookup лучше.(Мне бы хотелось, чтобы существовала версия ILookup, которая присваивала бы только одно значение ключу, а не группе.)

(Кстати, стоит отметить, что отношения между IEnumerable и IList чем-то похожи на отношения между ILookup и IDictionary — первый является неизменным, второй — нет.)

GroupBy и ToLookUp имеет почти такую же функциональность ЗА ИСКЛЮЧЕНИЕМ это: Ссылка

Группировка by:Оператор GroupBy возвращает группы элементов на основе некоторого значения ключа.Каждая группа представлена объектом IGrouping .

Посмотреть:ToLookup - это то же самое, что GroupBy;единственное отличие заключается в том, что выполнение GroupBy откладывается, тогда как выполнение ToLookup выполняется немедленно.

Давайте проясним разницу, используя пример кода.предположим, что у нас есть класс, представляющий Person Модель:

class Personnel
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public int Level { get; set; }
}

после этого мы определяем список personnels как показано ниже:

 var personnels = new List<Personnel>
    {
        new Personnel { Id = 1, FullName = "P1", Level = 1 },
        new Personnel { Id = 2, FullName = "P2", Level = 2 },
        new Personnel { Id = 3, FullName = "P3", Level = 1 },
        new Personnel { Id = 4, FullName = "P4", Level = 1 },
        new Personnel { Id = 5, FullName = "P5", Level =2 },
        new Personnel { Id = 6, FullName = "P6", Level = 2 },
        new Personnel { Id = 7, FullName = "P7", Level = 2 }
    };

Теперь мне нужно получить personnels сгруппированы по их уровню.Здесь у меня есть два подхода.используя GroupBy или ToLookUp.Если я использую GroupBy, как указывалось ранее, он будет использовать отложенное выполнение, это означает, что при выполнении итерации по коллекции следующий элемент может быть вычислен, а может и не быть вычислен до тех пор, пока он не будет вызван.

 var groups = personnels.GroupBy(p => p.Level);
    personnels.RemoveAll(p => p.Level == 1);
    foreach (var product in groups)
    {
        Console.WriteLine(product.Key);
        foreach (var item in product)
            Console.WriteLine(item.Id + " >>> " + item.FullName + " >>> " + item.Level);
    }

В приведенном выше коде я сначала сгруппировал personnels, но прежде чем повторить это, я удалил некоторые personnels.Как GroupBy использует отложенное выполнение, поэтому конечный результат не будет включать удаленные элементы, поскольку группировка будет выполняться в foreach укажи сюда.

Выходной сигнал:

2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2

Но если я перепишу приведенный выше код, как показано ниже: (обратите внимание, что код такой же, как и предыдущий код, за исключением GroupBy заменяется на ToLookUp)

 var groups = personnels.ToLookup(p => p.Level);
    personnels.RemoveAll(p => p.Level == 1);
    foreach (var product in groups)
    {
        Console.WriteLine(product.Key);
        foreach (var item in product)
            Console.WriteLine(item.Id + " >>> " + item.FullName + " >>> " + item.Level);
    }

Как ToLookUp использует немедленное выполнение, это означает, что когда я вызываю ToLookUp метод, генерируется результат и применяется группа, поэтому, если я удалю какой-либо элемент из personnels до начала итерации это не повлияет на конечный результат.

Выходной сигнал:

1
1 >>> P1 >>> 1
3 >>> P3 >>> 1
4 >>> P4 >>> 1
2
2 >>> P2 >>> 2
5 >>> P5 >>> 2
6 >>> P6 >>> 2
7 >>> P7 >>> 2

Примечание: GroupBy и ToLookUp оба также возвращают разные типы.

Вы могли бы использовать ToDictionary вместо ToLookup, но вам нужно обратить внимание на это:(ссылка)

Использование ToLookup() очень похоже на использование ToDictionary(), оба позволяют вам указывать селекторы ключей, селекторы значений и средства сравнения.Основное отличие заключается в том, что ToLookup() разрешает (и ожидает) дублирование ключей, тогда как ToDictionary() этого не делает

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top