在 ruby​​ 中将数字转换为单词 - 改进我的递归解决方案

Posted

技术标签:

【中文标题】在 ruby​​ 中将数字转换为单词 - 改进我的递归解决方案【英文标题】:Converting numbers to words in ruby - improving my recursion solution 【发布时间】:2016-06-09 23:19:39 【问题描述】:

问题是您将数字转换为单词 - 300 将转换为“三百”。我知道这个问题已经在堆栈溢出时得到解决,但我正在寻求一些关于我的特定递归解决方案的建议。

我的解决方案适用于除以下数字之外的所有数字: 100, 1000, 1000000

以上将返回“百”、“千”、“百万”。我明白为什么会这样。

300、3300、32000、35000 等。任何数字 % 100 或 1000 或 1000000 == 0 都将返回“三千三百零”。

我唯一成功的想法是使用第二种方法 get_words 在通过 in_words 运行数字后从解决方案中删除“零”,如果数字大于 0,则只返回“一”+数字而不是运行如果数字是 100/1000/1000000,则通过 in_words...

由于在此处使用递归的限制,我的解决方案可能只能这样工作,但也许我遗漏了一些东西。谁能提供一种方法来调整我的解决方案来解决这个问题?

NUMBER_DICTIONARY = 
  0 => "zero",
  1 => "one",
  2 => "two",
  3 => "three",
  4 => "four",
  5 => "five",
  6 => "six",
  7 => "seven",
  8 => "eight",
  9 => "nine",
  10 => "ten",
  11 => "eleven",
  12 => "twelve",
  13 => "thirteen",
  14 => "fourteen",
  15 => "fifteen",
  16 => "sixteen",
  17 => "seventeen",
  18 => "eighteen",
  19 => "nineteen",
  20 => "twenty",
  30 => "thirty",
  40 => "forty",
  50 => "fifty",
  60 => "sixty",
  70 => "seventy",
  80 => "eighty",
  90 => "ninety",
  100 => "hundred",
  1000 => "thousand",
  1000000 => "million"
  

def get_words(number)
  result = in_words(number)
  return  "one" + " " + NUMBER_DICTIONARY[number] if (number == 100 || number == 1000 || number == 1000000)
  return result.split(" ").delete_if  |word| word == "zero".join(" ") if result.include?("zero") && number > 0 
  result
end

def in_words(number)
  #base case
  return NUMBER_DICTIONARY[number] if NUMBER_DICTIONARY.include?(number)
  #recursion
  return in_words(number / 1000000) + " " + in_words(1000000) + " " + in_words(number % 1000000) if number > 1000000
  return in_words(number / 1000) + " " + in_words(1000) + " " + in_words(number % 1000) if number > 1000
  return in_words(number / 100) + " " + in_words(100) + " " + in_words(number % 100) if number > 100
  return in_words((number / 10) * 10) + " " + in_words(number % 10) if number > 20 

end

【问题讨论】:

【参考方案1】:

我能够使用默认参数修复您的递归算法:

SCALES = [1000000, 1000, 100]

def in_words(number, start = true)

  return 'negative ' + in_words(-number) if number < 0

  # One of the scales in spoken English
  return 'one ' + in_words(number, false) if SCALES.include?(number) and start

  #base case
  return NUMBER_DICTIONARY[number] if NUMBER_DICTIONARY.include?(number)

  SCALES.each do |n|
    if number > n
      result = []
      result << in_words(number/n)
      result << in_words(n, false)
      result << in_words(number % n, false) unless number % n == 0
      return result.join(' ')
    end
  end

  # This can only ever be reached when 100 > number > 20
  return in_words((number / 10) * 10) + " " + in_words(number % 10)
end

start 默认为真,表示这可能是scale in spoken English 的开始。如果数字在刻度的开头,它可能会以“一”为前缀。识别这些尺度也让我能够概括一些重复的代码。在刻度开始后查找数字的名称时,我将 start 设置为 false。

摆脱最后的“零”更加容易。如果一个位的数字为零,我们不会用英文说。

在我的测试中,连接字符串偶尔会导致单词之间出现额外的空格,因此我改为构建数组并加入它们。

最后,我添加了对负数的支持。

请注意:我在一堆我想到的边缘情况下对此进行了测试,但仍然可能存在潜伏的错误。

【讨论】:

以上是关于在 ruby​​ 中将数字转换为单词 - 改进我的递归解决方案的主要内容,如果未能解决你的问题,请参考以下文章

如何在java中将数字转换为泰语单词

在c ++中将单词转换为数字

如何在Ruby中将单词数组排序为字谜数组?

在 Ruby 中将 UTC 时间戳转换为 ISO 8601

在Swift或Objective-C中将大型混合数字和文本数字转换为数字

在Java中将句子字符串转换为单词的字符串数组