在尝试用循环变量填充数组数组时,我注意到了一种奇怪的行为。
N = 5
M = 4
m = Array.new(N, Array.new(M, -1))
for j in 0..N-1
m[j][0] = j
end
m
这样做最终会得到:
4 -1 -1 -1
4 -1 -1 -1
4 -1 -1 -1
4 -1 -1 -1
4 -1 -1 -1
但我期待:
0 -1 -1 -1
1 -1 -1 -1
2 -1 -1 -1
3 -1 -1 -1
4 -1 -1 -1
另一方面,这可以按预期工作:
N = 5
m = Array.new(N)
for i in 0..N-1
m[i] = i
end
puts m # => [0, 1, 2, 3, 4]
我在这里缺少什么?
答案 0 :(得分:8)
m = Array.new(N, Array.new(M, -1))
创建一个大小为N
的数组,其每个成员都是相同的对象 - 一个填充-1的大小M
数组。因此,当您设置内部数组的第一个元素时,将在每个外部数组中重新选择更改,因为它们都包含相同的对象。
相反,请使用块形式:
Array.new(N) { Array.new(M, -1) }
为外部数组的每个元素调用该块,使每个元素获得不同的新内部数组。
答案 1 :(得分:1)
只是做:
Array.new(N) { Array.new(M, -1) }
而不是:
Array.new(N, Array.new(M, -1))
阅读文档:
案例1:
创建给定大小的数组。通过将元素的索引传递给给定块并存储返回值来创建此数组中的每个元素。
示例:
ary_new_without_block = Array.new(3) { [] }
ary_new_without_block.map(&:object_id) # => [75888070, 75888060, 75888050]
查看对象id,它们都是不同的,这可以确保所有内部数组对象都不同。因此,如果更改任何内部数组对象,则不会在所有元素数组中看到更改:
ary_new_without_block[0] << 2
ary_new_without_block # => [[2], [], []]
案例2:
创建作为参数传递的数组的副本(通过在参数上调用#to_ary生成数组)。
示例:
ary_new_block = Array.new(3,[])
ary_new_block.map(&:object_id) # => [75888980, 75888980, 75888980]
查看对象id,它们都是相同的,这可以确保所有内部数组对象都没有区别。因此,如果更改一个内部数组对象,将在所有元素中看到更改:
ary_new_block[0] << 2
ary_new_block # => [[2], [2], [2]]
您选择第二种情况,因此您没有得到您想要的输出。但第一个案例将帮助您实现目标。