【问题标题】:Why doesn't this generate the lucky numbers?为什么这不会生成幸运数字?
【发布时间】:2017-04-01 23:39:46
【问题描述】:

我正在尝试编写一个生成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. 遍历它们并返回下一个幸运数字:

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

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

我不明白为什么这不能按我的意愿工作。

【问题讨论】:

  • 请记住,每次执行第 3 步时,您都会得到一个新序列。现在,您确定要从该新序列中获得元素 counter 吗?尝试在一张纸上完成所有内容...
  • @JonSkeet 我很确定,我想我应该每次都从上一代序列中提取下一个元素。但我可以在纸上试一试。
  • 鉴于维基百科有一个工作示例,我建议您在调试时遵循该示例。我注意到的第一个问题是你从第二个元素开始,因为你有counter = 1 而不是counter = 0。这意味着你永远不会返回 1,这是一个幸运数字。
  • 算法有点奇怪。对于第一个数字,采用 1 并删除每个 2nd 元素。对于所有以下数字,所采取的数字和朝向下一个擦除数字的步数相等。所以我猜你必须在进入实际的重新出现算法表单之前专门处理1

标签: c# iteration generator sequences


【解决方案1】:

您的代码无法正常工作的原因有两个:

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

【讨论】:

  • “我认为你将 counter 初始化为 1 以避免取消序列中的第 1 个数字”——这是真的。
猜你喜欢
  • 2011-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多