在 Ruby 中递归展平数组

4 ruby recursion

我很难理解为什么这段代码有效:

def flatten(array, result = [])
  array.each do |element|
    if element.is_a? Array
      flatten(element, result)
    else
      result << element
    end
  end
  result
end
Run Code Online (Sandbox Code Playgroud)

特别是,为什么它可以在不必将 flatten 方法调用的结果分配给结果数组的情况下工作,如下所示:

def flatten1(array, result = [])
  array.each do |element|
    if element.is_a? Array
      result = flatten(element, result)
    else
      result << element
    end
  end
  result
end
Run Code Online (Sandbox Code Playgroud)

两者都产生相同的输出:

p flatten [1,2,[3,4,[5,[6]]]]  # [1, 2, 3, 4, 5, 6]
p flatten1 [1,2,[3,4,[5,[6]]]] # [1, 2, 3, 4, 5, 6]
Run Code Online (Sandbox Code Playgroud)

Jör*_*tag 5

该flatten方法破坏性地修改了第result6 行中的第二个参数,并将修改后的数组作为参数传递给第 4 行中的递归调用。无需从该方法返回任何内容,因为作为第二个元素传递的任何数组都将被破坏性地修改为附加输入数组的扁平版本:

my_array = [:foo]

flatten([1, [2, [3, [4]]]], my_array)

my_array
#=> [:foo, 1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)

修改作为参数传递的对象或通过修改输入参数而不是仅仅返回它来返回值通常被认为是不好的形式。看起来代码是由想要使用第二个参数作为输出缓冲区的 C 程序员编写的。

一个更惯用的 Ruby 版本看起来像这样:

def flatten(array)
  array.each_with_object([]) do |element, result|
    if element.is_a?(Array)
      result.concat(flatten(element))
    else
      result << element
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

或者一个完全没有变化的纯功能版本:

def flatten(array)
  array.inject([]) do |result, element|
    result + if element.is_a?(Array)
      flatten(element)
    else
      [element]
    end
  end
end
Run Code Online (Sandbox Code Playgroud)