linq查询中的随机数

时间:2015-05-21 13:27:32

标签: c# linq random lazy-sequences

在运行时,惰性语句中的随机数据是否可能得到不同的评估?使用以下代码,我看到“哇”多次打印到控制台。但是,如果我强制查询结果(即在ToList()xs上调用ys),事情似乎正常。

    public static void Main(string[] args)
    {
        var generator = new Random();
        var xs = from x in Enumerable.Range(0, 20000)
                 select generator.Next();

        var ys = from y in Enumerable.Range(0, 5000)
                 select generator.Next();

        foreach (var x in xs)
        {
            var q1 = from y in ys where y > x select y;
            var q2 = from y in ys where y > x select y;

            if (!q1.SequenceEqual(q2))
                Console.WriteLine("wow!");
        }

        Console.WriteLine("done");
        Console.ReadLine();

    }

我怀疑这与linq查询“懒惰”的事实有关。这准确吗?

1 个答案:

答案 0 :(得分:2)

  

懒惰语句中的随机数据在运行时可能会得到不同的评估吗?

正如你所写的那样,真实的是:

  

我怀疑这与linq查询“懒惰”的事实有关。这准确吗?

另一个重要的事情是它们在执行后没有“物化”/“缓存”,因此每次执行它们时,它们都会被重新生成。

这一行

if (!q1.SequenceEqual(q2))
    Console.WriteLine("wow!");

将导致对q1q2枚举的评估,每个枚举都会导致ys的枚举。因此,对于ys周期的每个周期,foreach将“生成”两次。

因此,考虑到foreach周期将会产生20000个“cyles”,ys将“生成”40000次。

Random.Next()将执行20000 +(20000 * 2 * 5000)次,其中

20000: the xs sequence, used only once by the foreach cycle:
20000 * 2 * 5000: 20000 cycles in which the ys sequence is used twice

注意如果发生了什么:

var xs = (from x in Enumerable.Range(0, 20000)
         select generator.Next()).ToArray();

var ys = (from y in Enumerable.Range(0, 5000)
         select generator.Next()).ToArray();

这里我们“实现”数组中的枚举(准确地说是两个数组)。 Random.Next()将被称为20000 + 5000次的格式,它将直接在这两行中完成。枚举xsys不会导致生成新的随机数。