【问题标题】:Random numbers in linq querieslinq 查询中的随机数
【发布时间】:2015-05-21 13:27:31
【问题描述】:

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

    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 查询是“懒惰的”这一事实有关。这准确吗?

【问题讨论】:

  • LINQ 查询的“延迟执行”是最常被误解的功能之一。查询总是在迭代查询变量时执行,而不是在创建查询变量时执行。
  • 我真的很想提出一个答案,通过对ys 的每次迭代使用new Random 来“解决”这个问题,但我不知道该怎么做很明显:(
  • @Rawling from x in Enumerable.Range(0, 20000) let rnd = new Random() select rnd.Next();
  • @xanatos Nah,这似乎并没有做到 - 你会为每个 y 而不是每个 ys 获得一个 new Random,我认为这会减慢它的速度,以至于它坏了.
  • @Rawling 你说得对:(from useless in new int[1] let rnd = new Random() from x in Enumerable.Range(0, 20000) select rnd.Next()).ToArray();

标签: c# linq random lazy-sequences


【解决方案1】:

惰性语句中的随机数据是否会在运行时得到不同的评估?

如您所写,这是真的:

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

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

这一行

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

将导致q1q2 枚举的评估,每个都会导致ys 的枚举。所以ys 将在foreach 循环的每个循环中“生成”两次。

因此,考虑到foreach 循环将执行 20000 个“循环”,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的枚举不会导致新随机数的产生。

【讨论】:

  • 谢谢你——记住这一点很重要。
  • @rookie 我已经更新了回复,添加了另一篇文章。
  • 好的,谢谢。这或多或少是我在进入foreach 循环之前对查询调用ToList() 时注意到的。
猜你喜欢
  • 2016-05-21
  • 2010-12-11
  • 2021-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2017-04-12
相关资源
最近更新 更多