ILookup ( Поиск )<TKey, TVal=""> против.Игрогруппирование<TKey, TVal="">
Вопрос
У меня возникли проблемы с формулированием различий между 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>
Прав ли я в следующих аналогиях?
- Ан
IGrouping<TKey, TVal>
является единой группой (т. е.ключевая последовательность), аналогичнаяKeyValuePair<TKey, TVal>
где значение на самом деле представляет собой последовательность элементов (а не один элемент) - Ан
IEnumerable<IGrouping<TKey, TVal>>
является последовательностью из них (аналогично тому, что вы получаете при повторенииIDictionary<TKey, TVal>
- Ан
ILookup<TKey, TVal>
это больше похоже наIDictionary<TKey, TVal>
где значение на самом деле представляет собой последовательность элементов
Решение
Да, все это верно.
И ILookup<TKey, TValue>
также распространяется IEnumerable<IGrouping<TKey, TValue>>
поэтому вы можете перебирать все пары ключ/коллекция, а также (или вместо этого) просто искать определенные ключи.
Я в основном думаю о ILookup<TKey,TValue>
как будто IDictionary<TKey, IEnumerable<TValue>>
.
Имейте в виду, что ToLookup
— это операция «сделай это сейчас» (немедленное выполнение), тогда как GroupBy
откладывается.Так получилось, что из-за того, как работает «pull LINQ», когда вы начинаете тянуть IGrouping
s в результате 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() этого не делает