用于reduce / inject迭代器的Splat块参数

时间:2013-04-18 13:20:29

标签: ruby iterator block

我已经定义了一个这样的数组:

ary = [[0,1], [2,3]]

运行以下代码:

ary.reduce(nil) do |a, i, k|
  puts "#{a.inspect} #{i.inspect} #{k.inspect}"
end

在每次迭代中,我都希望变量aik分别保存累加器(nil)的值,第一个元素,以及内部数组的第二个元素,即我期望这个输出:

nil 0 1
nil 2 3

但结果却是:

nil [0, 1] nil
nil [2, 3] nil

为什么呢?我怎样才能达到我想要的效果?

此外,为什么使用map的以下代码正如我所期望的那样工作?

ary.map do |i, k|
  puts "#{i.inspect} #{k.inspect}"
end

# Output
# 0 1
# 2 3

有什么区别?

3 个答案:

答案 0 :(得分:5)

Splat可以在一个级别上工作。使用map时,阻止参数为[0, 1],依此类推,可以将其扩展为01。对于inject,块参数为nil[0, 1],可以将其分配给两个变量(不包括splat),但不能分配给三个变量。 Splat在这里不起作用,因为它们已经被喷溅(它们是两个变量)。为了展开[0, 1],您需要在数组中执行此操作,这需要一对括号。

{|a, (i, j)| ...}

答案 1 :(得分:3)

你想这样做:

A.reduce(nil) { |a, (i, j)| p i }

mapreduce的默认行为之间的差异是由于Ruby处理接收单个参数的块的特殊方式。在这种情况下(即map),它为您拼出一个数组,但对于一个接收多个参数的块(如reduce),它需要帮助找出你想要它的内容做。

答案 2 :(得分:2)

让我们尝试下面的内容,以便更好地理解:

A = [[0,1], [2,3], [4,5], [6,7]]
A.map { |i| print i } #=> [0, 1][2, 3][4, 5][6, 7]

A = [[0,1], [2,3], [4,5], [6,7]]
A.map { |i,j| print i,j ;print " " } #=> 01 23 45 67

这是因为在第二个代码中,每个元素以下面的方式发生的内部赋值传递给块:

i,j = [0,1]
i,j = [2,3] so on.

在第一段代码中,它的工作原理如下:

i = [0,1]
i = [2,3] so on.

所以Array#map效果很好。现在,在您的情况下,您没有打印j,只打印i,因此您获得单个值。

A = [[0,1], [2,3], [4,5], [6,7]]
A.map { |i,j| print i ;print " " } #=> 0 2 4 6

现在要更好地了解Enum#inject,请参阅A Simple Pattern for Ruby's inject method。和Ruby's inject() and collect()