我正在使用Ruby 2.3.1,我无法判断我是否遇到过错误或者这是否是预期的行为。
如果通过制作嵌套数组来创建NxN矩阵,那么:
matrix = [[0]*5]*5
然后在对角线上设置元素,如下:
(0..4).each {|i| matrix[i][i] = i}
这最终影响到每一行中的每一列:
[
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]
]
这是预期的行为吗?
P.S。我不想使用Ruby的Matrix库,而是宁愿使用普通数组。
提前致谢:)
答案 0 :(得分:1)
在Ruby中,数组在幕后是array
类型的对象,它们可以包含基本类型和对其他对象的引用。现在,最后一点很重要 - 数组不包含对象本身,而是指向它的指针,当程序员要求时,它被解释为必要的。
OP的原始初始化代码
matrix = [[0]*5]*5
真正创建一个包含5个0的array
个对象,然后将指针复制到它5次。
matrix = Array.new(5, Array.new(5, 0))
出于同样的原因。因此,正如在评论中发布的那样,用于创建5个不同array
对象的数组的惯用正确的Ruby方法是
matrix = Array.new(5){Array.new(5, 0)}
这会产生一个包含指向5个不同 array
个对象的指针的数组,从而防止OP遇到问题。有关Ruby数组行为的完整文档可以在finely-crafted link找到。
答案 1 :(得分:1)
您无需更改对角线即可观察到该行为;只需改变任何元素,比如说
matrix[1][1] = 1
然后
matrix
#=> [[0, 1, 0, 0, 0], [0, 1, 0, 0, 0], [0, 1, 0, 0, 0],
# [0, 1, 0, 0, 0], [0, 1, 0, 0, 0]]
考虑
matrix.map { |row| row.object_id }
#=> [70153694327100, 70153694327100, 70153694327100,
# 70153694327100, 70153694327100].
这表明matrix
的所有元素(“行”)都是同一个对象,因为如果更改了该对象,matrix
的所有元素都会受到影响。 matrix = [[0]*5]*5
相当于
matrix = Array.new(5, Array.new(5,0))
(参见Array::new,尤其是“常见陷阱”。)你想要的是什么(如@Sebastian所说)
matrix = Array.new(5) { Array.new(5,0) }
#=> [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
这样
matrix[1][1] = 1
仅影响那一个元素:
matrix
#=> [[0, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
答案 2 :(得分:0)
matrix = [[0]*5]*5
让我们打破这个:
a = [0]*5
创建一个包含5个零的数组;这是一个整数数组。
matrix = [a] * 5
为同一个数组a
创建一个包含5个引用的数组。
当然,当你修改一个时,其他的将被修改;它是相同的数组。
我不认识Ruby,所以请随意纠正任何不正确的术语。