在自己内部调用方法是不好的做法吗?

时间:2015-07-09 03:12:18

标签: ruby coding-style

我正在创建一个简短的程序来查找给定数字集的平均值。这是一个程序,其基本结构首先在TI-83上用goto语句编写,所以我对这种事情的正确实践有点不确定。这是相关代码:

$sum     = 0
$counter = 0

def average
  puts "Input another number, or \"end\" to end."
  input = gets.chomp
  if input == "end"
    puts $counter
    puts ($sum / $counter).to_f
  else
    $sum += input.to_f
    $counter += 1
    puts $counter
    average #Here the method is called again, repeating the cycle.
  end
end

我不确定如何做到这一点,因为像这样构建的代码点是它可以处理不确定数量的输入,因此它重复性质。

3 个答案:

答案 0 :(得分:5)

在具有所谓的“尾调用优化”的语言中,这种结构是循环的主要方式。然而,Ruby却没有;递归(重新输入已经输入的函数)是常用的,但不能作为简单循环的一般替代,就像在这种情况下一样。

此处,正如pvg所述,while(或等效地,until)循环更好:

sum = 0
counter = 0
puts "Input a number, or \"end\" to end."
input = gets.chomp
until input == "end"
  sum += input.to_f
  counter += 1
  puts "Input another number, or \"end\" to end."
  input = gets.chomp
end
puts sum / counter

或带有break的无限循环:

sum = 0
counter = 0
loop do
  puts "Input a number, or \"end\" to end."
  input = gets.chomp
  break if input == "end"
  sum += input.to_f
  counter += 1
end
puts sum / counter

但你也可以使用更多的Ruby方式:

puts 'Input numbers, or "end" to end.'
array = STDIN.each_line.lazy
  .map(&:chomp)
  .take_while { |line| line != "end" }
  .map(&:to_f)
  .to_a
puts array.inject(&:+) / array.size

或者更丑陋但内存效率更高:

puts 'Input numbers, or "end" to end.'
sum, count = *STDIN.each_line.lazy
  .map(&:chomp)
  .take_while { |line| line != "end" }
  .inject([0, 0]) { |memo, x|
    [memo[0] + x.to_f, memo[1] + 1]
  }
puts sum / count

答案 1 :(得分:1)

是的,一种方法可以调用自己。这称为递归,是编程和计算机科学中非常重要的概念。

您需要的只是一个基本案例和对自己的调用。在您的示例中,基本情况是

if input == "end"
    puts $counter
    puts ($sum / $counter).to_f

并且重复步骤是

else
    $sum += input.to_f
    $counter += 1
    puts $counter
    average #Here the method is called again, repeating the cycle.

答案 2 :(得分:1)

这不是一个新答案,而是一个支持@ adao7000答案的插图示例。

递归可以是一个非常强大的工具。最好的例子之一是遍历嵌套数组或散列。递归允许您定义如何一次提取数据,然后在每个级别使用相同的过程 - 而无需知道有多少级别。

这是一个简单的例子:

nested_array = [
  'level 1',
  [
    'level 2'
  ],
  [
    [
      'level 3',
      [
        'level 4'
      ]
    ]
  ]
]

def print_values(element)

  if element.kind_of? Array
    element.each{|e|  print_values(e)}
  else
    puts element 
  end

end

print_values nested_array

请注意print_values方法如何打印出当前值或将子数组传回给自己。