我已经定义了一个这样的数组:
ary = [[0,1], [2,3]]
运行以下代码:
ary.reduce(nil) do |a, i, k|
puts "#{a.inspect} #{i.inspect} #{k.inspect}"
end
在每次迭代中,我都希望变量a
,i
和k
分别保存累加器(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
有什么区别?
答案 0 :(得分:5)
Splat可以在一个级别上工作。使用map
时,阻止参数为[0, 1]
,依此类推,可以将其扩展为0
和1
。对于inject
,块参数为nil
和[0, 1]
,可以将其分配给两个变量(不包括splat),但不能分配给三个变量。 Splat在这里不起作用,因为它们已经被喷溅(它们是两个变量)。为了展开[0, 1]
,您需要在数组中执行此操作,这需要一对括号。
{|a, (i, j)| ...}
答案 1 :(得分:3)
你想这样做:
A.reduce(nil) { |a, (i, j)| p i }
map
和reduce
的默认行为之间的差异是由于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()