为什么这不会产生幸运数字?

Why doesn't this generate the lucky numbers?

我正在尝试编写一个生成 lucky numbers

的函数
static IEnumerable<int> LuckyNumbers()
{
  IEnumerable<int> luckyNumbers = Enumerable.Range(1, int.MaxValue);
  int counter = 1;
  while (true)
  {
    int number = luckyNumbers.ElementAt(counter++);
    yield return number;
    luckyNumbers = luckyNumbers.Where((_, index) => (index + 1) % number != 0);
  }
}

但这会生成:

2,5,7,11,13,17,21,...

这不是幸运数字。

为什么我的代码不起作用?我正在尝试:

  1. 从所有自然数开始:

    IEnumerable<int> luckyNumbers = Enumerable.Range(1, int.MaxValue);
    int counter = 1;
    
  2. 遍历它们并return下一个幸运数字:

    while (true)
    {
      int number = luckyNumbers.ElementAt(counter++);
      yield return number;
    
  3. 从序列中删除所有第 n 个数字:

    luckyNumbers = luckyNumbers.Where((_, index) => (index + 1) % number != 0);
    

我不明白为什么这不符合我的预期。

您的代码不起作用的原因有几个:

  1. 编程中的集合是零索引的。这就是为什么您生成的第一个数字是 2,因为它是索引为 1 的数字。您应该将 counter 初始化为 0。
  2. 我认为您将计数器初始化为 1 以避免取消序列中的第 1 个数字(这将有效地杀死所有数字,因此在给定位置获取元素注定会失败)。问题在于这里幸运数字的定义:虽然第一个幸运数字是 1,但第一次迭代是敲击每个 second 个数字。所以你必须拿 Math.Min(number, 2).

最后,您得出以下结果:

    static IEnumerable<int> LuckyNumbers()
    {
        IEnumerable<int> luckyNumbers = Enumerable.Range(1, int.MaxValue);
        int counter = 0;
        while (true)
        {
            int number = luckyNumbers.ElementAt(counter++);
            yield return number;
            int moduloCheck = Math.Max(number, 2);
            luckyNumbers = luckyNumbers.Where((_, index) => (index + 1) % moduloCheck != 0);
        }
    }

不过,从性能的角度来看,我认为该解决方案对于大数字来说很糟糕,因为您将永远在 ElementAt 处反复检查第一个数字。因为 where 表达式不可索引,所以这将始终开始检查每个数字的几个 where 条件。好处是你可以简单地将它用作 LuckyNumbers().Take(n) 来获得第一个 n 个幸运数字。