Я недавно был в ситуации, когда мне нужно было выполнить операцию, сгруппированную медленно, получая запрос Linq.«Lazy» GroupBy with Linq
Теперь groupBy теряет свою ленивость, это означает, что вам нужно дождаться завершения всей последовательности, пока вы не получите какие-либо группы. Это для меня логически кажется не лучшим решением, так как группа может быть возвращена сразу после ее первой встречи.
Я написал следующий код, который, кажется, работает нормально, и я ищу подводные камни и общие улучшения, а также мысли о самой концепции (например, может/должен метод groupBy возвращать группы как можно скорее) ,
public static IEnumerable<KeyValuePair<R, IEnumerable<T>>> GroupByLazy<T, R>(this IEnumerable<T> source, Func<T, R> keySelector)
{
var dic = new Dictionary<R, BlockingCollection<T>>();
foreach (var item in source)
{
var Key = keySelector(item);
BlockingCollection<T> i;
if (!dic.TryGetValue(Key, out i))
{
i = new BlockingCollection<T>();
i.Add(item);
dic.Add(Key, i);
yield return new KeyValuePair<R, IEnumerable<T>>(Key, i);
}
else i.TryAdd(item);
}
// mark all the groups as completed so that enumerations of group-items can finish
foreach (var groupedValues in dic.Values)
groupedValues.CompleteAdding();
}
Простой тест:
var slowIE = Observable.Interval(TimeSpan.FromSeconds(1)).ToEnumerable().Take(10);
var debug = slowIE.Do(i => Console.WriteLine("\teval " + i));
var gl = debug.GroupByLazy(i => i % 2 == 0);
var g = debug.GroupBy(i => i % 2 == 0);
Console.WriteLine("Lazy:");
gl.Run(i => Console.WriteLine("Group returned: " + i.Key));
Console.WriteLine(gl.Single(i => i.Key).Value.Count());
Console.WriteLine("NonLazy:");
g.Run(i => Console.WriteLine("Group returned: " + i.Key));
Console.WriteLine(g.Single(i => i.Key).Count());
Console.ReadLine();
который печатает:
Lazy:
eval 0
Group returned: True
eval 1
Group returned: False
eval 2
eval 3
eval 4
eval 5
eval 6
eval 7
eval 8
eval 9
NonLazy:
eval 0
eval 1
eval 2
eval 3
eval 4
eval 5
eval 6
eval 7
eval 8
eval 9
Group returned: True
Group returned: False
Как вы можете видеть, в моей LazyGroupBy группы возвращаются, как только они впервые встретились, и может, таким образом, действовать, не дожидаясь сгруппировки всей последовательности.
Мысли?
Редактировать: быстро подумал, я думаю, что «Lazy» - неправильный термин ... Я не носитель языка, какой термин я действительно ищу?
Вы сразу же получите группу, но вы будете уверены, что у группы есть все ее участники только после того, как весь исходный текст был повторен. Так что если вы просто заботитесь о ключах - есть лучшие способы извлечь только групповые ключи, хотя ... –
Не уверен, что это на 100% подходит, но мне интересно, [Push LINQ] (http://msmvps.com /blogs/jon_skeet/archive/2008/01/04/quot-push-quot-linq-revisited-next-attempt-at-an-explanation.aspx) может помочь здесь –