为什么.to_s会破坏此代码?

时间:2015-08-03 17:54:35

标签: ruby string fixnum

我正在处理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中使用Big Integers进行测试   但不是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  `
'

2 个答案:

答案 0 :(得分:4)

您以递归方式调用此函数。如果你计算了阶乘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

答案 1 :(得分:0)

首先,Factorial仅定义在非负数上,因此您的第一个测试不正确(如果nb <= 0)。当数字为0时递归应该停止,并且在该点应该返回1。

因为你的递归返回一个字符串而不是一个数字,所以你不能在下一轮递归中将字符串乘以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中对尾调用优化,递归和返回值进行一些研究。这将允许您更好地实现递归函数。

快乐的编码!