Does ToLookup forces immediate execution of a sequence

邮差的信 提交于 2021-01-03 06:50:02

问题


I was looking into Enumerable.ToLookup API which converts an enumerable sequence into a dictionary type data structure. More details can be found here:

https://msdn.microsoft.com/en-us/library/system.linq.enumerable.tolookup(v=vs.110).aspx

The only difference it carries from ToDictionary API is the fact that it won't give any error if the key selector results in duplicate keys. I need a comparison of deferred execution semantics of these two APIs. AFAIK ToDictionary API results in immediate execution of sequence i.e. it doesn't follow deferred execution semantics of LINQ queries. Can anyone help me with the deferred execution behavior of ToLookup API? Is it the same as ToDictionary API or any different?


回答1:


Easy enough to test...

void Main()
{
    var lookup = Inf().ToLookup(i => i / 100);
    Console.WriteLine("if you see this, ToLookup is deferred"); //never happens
}

IEnumerable<int> Inf()
{
    unchecked
    {
        for(var i=0;;i++)
        {
            yield return i;
        }
    }
}

To recap, ToLookup greedily consumes the source sequence without deferring.

In contrast, the GroupBy operator is deferred, so you can write the following to no ill-effect:

var groups = Inf().GroupBy(i => i / 100); //oops

However, GroupBy is greedy, so when you enumerate, the entire source sequence is consumed.

This means that

groups.SelectMany(g=>g).First();

also fails to complete.

When you think about the problem of grouping, it quickly becomes apparent that when separating a sequence into a sequence of groups, it would be impossible to know if even just one of the groups were complete without completely consuming the entire sequence.




回答2:


This was sort of covered here, but it was hard to find!

In short -- ToLookup does not defer execution!

  • ToLookup() -> immediate execution
  • GroupBy() (and other query methods) -> deferred execution



回答3:


If you look at the reference implementation source code for both the Enumerable.ToDictionary() and the Enumerable.ToLookup() methods, you will see that both end up executing a foreach loop over the source enumerable. That's one way to confirm that the execution of the source enumerable is not deferred in both cases.

But I mean, the answer is pretty self evident in that if you start off with an enumerable, and the return value of the function is no longer an enumerable, then clearly, it must have been executed (consumed), no?

(That last paragraph was not accurate as pointed out by @spender in the comments)



来源:https://stackoverflow.com/questions/38928613/does-tolookup-forces-immediate-execution-of-a-sequence

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!