【问题标题】:Why does .to_s break this code?为什么 .to_s 会破坏此代码?
【发布时间】:2015-08-03 17:54:34
【问题描述】:

我正在处理 Codewars Ruby 问题,但不明白我看到的错误。以下是说明:

用阶乘编码十进制数是一种写出数字的方法 在一个依赖阶乘而不是幂的基础系统中 数字。在此系统中,最后一位数字始终为 0,并且以 0 为基数! 之前的数字是 0 或 1,并且以 1 为基数!数字 在此之前是 0、1 或 2,并且以 2 为底!更普遍, 总是 0、1、2、... 或 n 中的倒数第 n 个数字,并且以 n! 为基数。

示例:十进制数 463 编码为“341010”

因为 463(以 10 为底)= 3×5! + 4×4! + 1×3! + 0×2! + 1×1! + 0×0!

如果我们仅限于数字 0...9,我们可以编码的最大数字是 10! - 1.

所以我们用字母 A 到 Z 扩展 0..9。有了这 36 个数字,我们可以 代码高达36! − 1 = 37199332678990121746799944815083519999999910 (以 10 为基数)

我们编写两个函数,第一个将编写一个十进制数,然后 返回具有阶乘表示的字符串: "dec2FactString(nb)"

第二个将解码具有阶乘表示的字符串 并产生十进制表示:“factString2Dec(str)”。

给定的数字将是正数。

注意

您可以希望在 Clojure、Python、Ruby、Haskel 中使用大整数进行测试 但不适用于 Java 和其他数字“nb”在 "dec2FactString(nb)" 最多长。

参考:http://en.wikipedia.org/wiki/Factorial_number_system

def dec2FactString(nb)
  if nb <= 0 then
    num = 1
  else
    num = (nb * dec2FactString(nb - 1))
  end
  return num
end

请注意,这种方法只是问题的前半部分。此代码似乎可以工作,因为它返回正确的阶乘,在使用此测试时作为 Fixnum:

Test.assert_equals(dec2FactString(4), "24") 

由于说明要求输入字符串,我通常认为只需将“.to_s”添加到 num 变量就可以解决这个问题,但我看到的是一致的“字符串不能被强制转换为 Fixnum (TypeError)”错误信息。我尝试将输出推送到数组并从那里打印,但看到了同样的错误。

我对 Fixnum 进行了一些阅读,并且我理解在将 Fixnum 添加到字符串方面的错误不起作用,但我认为在这种情况下我不会这样做 - 我只是想转换Fixnum 输出成一个字符串。我错过了什么吗?

观察 - 此代码中断并在其下方产生错误:

def dec2FactString(nb)
  if nb <= 0 then
    num = 1
  else
    num = (nb * dec2FactString(nb - 1))
  end
  return num.to_s
end

Example from description
 `*': String can't be coerced into Fixnum (TypeError)
    from `dec2FactString'
    from  `dec2FactString'
    from  `dec2FactString'
    from  `dec2FactString'
    from  `block in 
'
    from  `block in describe'
    from  `measure'
    from  `describe'
    from  `
'

【问题讨论】:

    标签: ruby string fixnum


    【解决方案1】:

    您正在递归调用此函数。如果您计算了 1 的阶乘并将 to_s 留在其中,那很好,因为您没有重复使用该变量。

    但是,如果您确实将to_s 放在那里,您希望num = (nb * dec2FactString(nb - 1)) 的结果是什么? dec2FactString 将返回 str 而不是 Fixnum,并且您不能/不应该能够在数字和字符串之间进行乘法运算。

    您可以做的是通过创建两种方法来拆分字符串化和计算的职责——一种委托给递归函数,另一种将其结果强制转换为字符串。

    def dec2FactString(nb)
        return fact(nb).to_s
    end
    
    def fact(nb)
        if nb <= 0 then
            1
        else
            nb * fact(nb - 1)
        end
    end
    

    【讨论】:

      【解决方案2】:

      首先,阶乘仅在非负数上定义,因此您的第一个测试不正确(如果 nb

      因为您的递归返回的是字符串而不是数字,所以您不能在下一轮递归中将字符串乘以 Fixnum。您的递归可以通过替换方法扩展为以下内容。

      dec2FactString(5)
      5 * dec2FactString(4)
      5 * 4 * dec2FactString(3)
      5 * 4 * 3 * dec2FactString(2)
      5 * 4 * 3 * 2 * dec2FactString(1)
      5 * 4 * 3 * 2 * 1 * dec2FactString(0)
      5 * 4 * 3 * 2 * 1 * "1"
      

      ...这是递归以错误结束的点,因为 dec2FactString(0) 返回“1”

      最好把它分成两个函数。一种递归计算阶乘,另一种将最终答案转换为字符串。此外,您不需要在 Ruby 中显式返回值。函数的最后一行是返回值。

      我不会给你完整的代码,因为你不会学到任何东西。作为一些提示,对 Ruby 中的尾调用优化、递归和返回值进行一些研究。这将使您能够更好地实现递归函数。

      编码愉快!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-02-08
        • 1970-01-01
        • 2012-10-08
        • 1970-01-01
        • 2016-12-12
        • 2011-05-30
        • 1970-01-01
        相关资源
        最近更新 更多