【问题标题】:Does ToLookup forces immediate execution of a sequenceToLookup 是否强制立即执行序列
【发布时间】:2016-08-13 02:25:55
【问题描述】:

我正在研究Enumerable.ToLookup API,它将可枚举序列转换为字典类型的数据结构。更多细节可以在这里找到:

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

它与ToDictionary API 的唯一区别是,如果键选择器导致重复键,它不会给出任何错误。我需要比较这两个 API 的延迟执行语义。 AFAIK ToDictionary API 导致立即执行序列,即它不遵循 LINQ 查询的延迟执行语义。谁能帮我解决ToLookup API 的延迟执行行为?是和ToDictionary API 一样还是不一样?

【问题讨论】:

    标签: c# .net linq


    【解决方案1】:

    很容易测试...

    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;
            }
        }
    }
    

    回顾一下,ToLookup 贪婪地消耗源序列而不延迟。

    相比之下,GroupBy 运算符 是延迟的,因此您可以编写以下内容而不会产生不良影响:

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

    但是,GroupBy贪婪的,所以当你枚举时,整个源序列都被消耗掉了。

    这意味着

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

    也未能完成。

    当您考虑分组问题时,很快就会发现,当将一个序列分成一组序列时,如果不完全消耗整个序列,就不可能知道其中一个组是否完整。

    【讨论】:

    • 我认为这有一个错误,因为它说首先 GroupBy 被推迟,然后它是贪婪的......是两者兼而有之吗?
    • @NathanBellowe 您是否将延迟与贪婪混淆了?它们是不同的行为。
    • 喜欢你的代码 sn-p 以帮助理解立即执行。非常好。程序最终由于无限循环而崩溃,因为 Lookup API 在 WriteLine 语句被命中之前继续创建其内部结构。
    【解决方案2】:

    这有点像here,但很难找到!

    简而言之——ToLookup 不会延迟执行!

    • ToLookup() -> 立即执行
    • GroupBy()(和其他查询方法)-> 延迟执行

    【讨论】:

    • 这个答案的最后一行启发我在我的答案中写了一些关于GroupBy 的内容。 GroupBy 被延迟但贪婪。
    • 删除,因为你的覆盖了它,我做了轻微的编辑
    【解决方案3】:

    如果您查看Enumerable.ToDictionary()Enumerable.ToLookup() 方法的参考实现源代码,您将看到它们最终都在源可枚举对象上执行foreach 循环。这是确认源可枚举的执行在两种情况下都不会延迟的一种方法。

    但是我的意思是,答案很明显,如果你从一个可枚举开始,并且函数的返回值不再是一个可枚举,那么很明显,它一定已经被执行(消耗) ,不是吗?

    (正如@spender 在 cmets 中指出的那样,最后一段并不准确)

    【讨论】:

    • 返回值可枚举的。这是IEnumerable&lt;IGrouping&lt;TKey, TElement&gt;&gt;
    • @spender:你一定指的是Enumerable.GroupBy()函数。
    • 不,我指的是从ToLookup返回的interface ILookup&lt;TKey, TElement&gt; : IEnumerable&lt;IGrouping&lt;TKey, TElement&gt;&gt;, IEnumerable
    • 我注意到我在上次编辑之后 投了反对票。如果我的回答仍然存在明显的不准确之处,请不要羞于发表评论。我不会生气的,我保证。恰恰相反:)
    猜你喜欢
    • 2013-10-23
    • 2013-10-20
    • 2015-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    相关资源
    最近更新 更多