each_with_object 的累加器不断重新初始化
Accumulator for each_with_object keeps re-initializing
我正在尝试编写广义笛卡尔积,其中 [n1, n2, ...ni] 的输入数据生成的输出数据是 [m1, m2, ...mi] 数组,适用于所有mj 使得 0 <= mj < nj。我知道下面的例程会产生一个有点折叠的版本,但我试图让示例代码尽可能简单。我的直接问题是第二个块变量(累加器),据我所知应该为块的每次迭代更新,但没有这样做:
#!/usr/bin/ruby
def gcp(dims)
first = dims.shift
dims.each_with_object((0...first).to_a) do |dim, v|
puts "\nv: #{v}, dim: #{dim}"
p v.product((0...dim).to_a)
end
end
gcp([3,2,4])
这会产生以下输出:
v: [0, 1, 2], dim: 2
[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]
v: [0, 1, 2], dim: 4
[[0, 0], [0, 1], [0, 2], [0, 3], [1, 0], [1, 1], [1, 2], [1, 3], [2, 0], [2, 1], [2, 2], [2, 3]]
p
方法是passthrough,所以block的return值在第一次迭代时应该是[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]
,也就是[=15=的值] 在第二次迭代中,除非我严重误解 each_with_object
.
我承认我不完全理解这个问题,但我已经解决了一个类似的问题,可以解释为什么 v
没有被您的代码更新。
让我们逐步查看您的代码,return获得所需的结果,而不是一路显示它。
dims = [3,2,4]
first = dims.shift
#=> 3
dims
#=> [2, 4] dims
表达式
dims.each_with_object((0...first).to_a) do |dim, v|
v.product((0...dim).to_a)
end
实际上与
相同
v = []
dims.each do |dim|
v.product((0...dim).to_a)
end
v #=> []
v
最后仍然是一个空数组应该不足为奇,因为 v
的值在循环中没有改变。 v.product((0...dim).to_a)
的 return 值被发射到 space,再也看不到了。您需要在循环中使用赋值语句。
现在考虑以下问题。
dims = [3,2,4]
v = []
dims.each do |n|
v << (0...n).to_a
end
v #=> [[0, 1, 2], [0, 1], [0, 1, 2, 3]]
(或v.push((0..n).to_a)
)。要使用 Enumerable#each_with_object,我们将修改上面的代码,删除第一个 (v = []
) 和最后一个 (v
) 语句,将 each
更改为 each_with_object([])
(参数作为对象的初始值,该方法将 return) 并添加一个块变量 v
,它保存对象:
dims.each_with_object([]) do |n,v|
v << (0...n).to_a
end
#=> [[0, 1, 2], [0, 1], [0, 1, 2, 3]]
我们可以使用 Emumerable#map 来简化它:
dims.map do |n|
(0...n).to_a
end
#=> [[0, 1, 2], [0, 1], [0, 1, 2, 3]]
根据您的需要,您可能更喜欢使用 Emumerable#flat_map:
dims.flat_map do |n|
(0...n).to_a
end
#=> [0, 1, 2, 0, 1, 0, 1, 2, 3]
每次迭代得到相同的对象,所以你要么需要改变块内的对象,要么使用 reduce
.
def gcp(dims)
first = dims.shift
dims.reduce((0...first).to_a) do |v, dim|
puts "\nv: #{v}, dim: #{dim}"
p v.product((0...dim).to_a)
end
end
gcp([3,2,4])
结果:
v: [0, 1, 2], dim: 2
[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]
v: [[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]], dim: 4
[[[0, 0], 0], [[0, 0], 1], [[0, 0], 2], [[0, 0], 3], [[0, 1], 0], [[0, 1], 1], [[0, 1], 2], [[0, 1], 3], [[1, 0], 0], [[1, 0], 1], [[1, 0], 2], [[1, 0], 3], [[1, 1], 0], [[1, 1], 1], [[1, 1], 2], [[1, 1], 3], [[2, 0], 0], [[2, 0], 1], [[2, 0], 2], [[2, 0], 3], [[2, 1], 0], [[2, 1], 1], [[2, 1], 2], [[2, 1], 3]]
我正在尝试编写广义笛卡尔积,其中 [n1, n2, ...ni] 的输入数据生成的输出数据是 [m1, m2, ...mi] 数组,适用于所有mj 使得 0 <= mj < nj。我知道下面的例程会产生一个有点折叠的版本,但我试图让示例代码尽可能简单。我的直接问题是第二个块变量(累加器),据我所知应该为块的每次迭代更新,但没有这样做:
#!/usr/bin/ruby
def gcp(dims)
first = dims.shift
dims.each_with_object((0...first).to_a) do |dim, v|
puts "\nv: #{v}, dim: #{dim}"
p v.product((0...dim).to_a)
end
end
gcp([3,2,4])
这会产生以下输出:
v: [0, 1, 2], dim: 2
[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]
v: [0, 1, 2], dim: 4
[[0, 0], [0, 1], [0, 2], [0, 3], [1, 0], [1, 1], [1, 2], [1, 3], [2, 0], [2, 1], [2, 2], [2, 3]]
p
方法是passthrough,所以block的return值在第一次迭代时应该是[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]
,也就是[=15=的值] 在第二次迭代中,除非我严重误解 each_with_object
.
我承认我不完全理解这个问题,但我已经解决了一个类似的问题,可以解释为什么 v
没有被您的代码更新。
让我们逐步查看您的代码,return获得所需的结果,而不是一路显示它。
dims = [3,2,4]
first = dims.shift
#=> 3
dims
#=> [2, 4] dims
表达式
dims.each_with_object((0...first).to_a) do |dim, v|
v.product((0...dim).to_a)
end
实际上与
相同v = []
dims.each do |dim|
v.product((0...dim).to_a)
end
v #=> []
v
最后仍然是一个空数组应该不足为奇,因为 v
的值在循环中没有改变。 v.product((0...dim).to_a)
的 return 值被发射到 space,再也看不到了。您需要在循环中使用赋值语句。
现在考虑以下问题。
dims = [3,2,4]
v = []
dims.each do |n|
v << (0...n).to_a
end
v #=> [[0, 1, 2], [0, 1], [0, 1, 2, 3]]
(或v.push((0..n).to_a)
)。要使用 Enumerable#each_with_object,我们将修改上面的代码,删除第一个 (v = []
) 和最后一个 (v
) 语句,将 each
更改为 each_with_object([])
(参数作为对象的初始值,该方法将 return) 并添加一个块变量 v
,它保存对象:
dims.each_with_object([]) do |n,v|
v << (0...n).to_a
end
#=> [[0, 1, 2], [0, 1], [0, 1, 2, 3]]
我们可以使用 Emumerable#map 来简化它:
dims.map do |n|
(0...n).to_a
end
#=> [[0, 1, 2], [0, 1], [0, 1, 2, 3]]
根据您的需要,您可能更喜欢使用 Emumerable#flat_map:
dims.flat_map do |n|
(0...n).to_a
end
#=> [0, 1, 2, 0, 1, 0, 1, 2, 3]
每次迭代得到相同的对象,所以你要么需要改变块内的对象,要么使用 reduce
.
def gcp(dims)
first = dims.shift
dims.reduce((0...first).to_a) do |v, dim|
puts "\nv: #{v}, dim: #{dim}"
p v.product((0...dim).to_a)
end
end
gcp([3,2,4])
结果:
v: [0, 1, 2], dim: 2
[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]
v: [[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]], dim: 4
[[[0, 0], 0], [[0, 0], 1], [[0, 0], 2], [[0, 0], 3], [[0, 1], 0], [[0, 1], 1], [[0, 1], 2], [[0, 1], 3], [[1, 0], 0], [[1, 0], 1], [[1, 0], 2], [[1, 0], 3], [[1, 1], 0], [[1, 1], 1], [[1, 1], 2], [[1, 1], 3], [[2, 0], 0], [[2, 0], 1], [[2, 0], 2], [[2, 0], 3], [[2, 1], 0], [[2, 1], 1], [[2, 1], 2], [[2, 1], 3]]