2016-08-13 3 views
0

私はRuby 2.3.1を使用していますが、私はバグが発生したのか、これが意図された動作なのかわかりません。Ruby配列での奇妙な動作ですか?

あなたのような、ネストされた配列を作成することにより、N×N個の行列を作成する場合:その後、

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

これは正しい方法です: 'Array.new(n){Array.new(n、0)}'詳細については完全にはわかりません – DaniG2k

+5

"コンパイラ/通訳/何でも " - これはかなり偽です。 –

+0

@Sergio、それは通常ハードウェアエラーであるからです。 –

答えて

1

Rubyでは配列は背後にあり、プリミティブ型と他のオブジェクトへの参照を含むことができるタイプarrayのオブジェクトです。さて、この最後のビットは重要です。配列にはオブジェクト自体は含まれておらず、代わりにポインタがあります。プログラマがそれを要求したときに必要に応じて解釈されます。

だからOPの元の初期化コード

matrix = [[0]*5]*5 

は実際にそれを5回、次いで5つの0、及びコピーポインタを含む単一arrayオブジェクトを作成します。この場合も同様の理由により、

matrix = Array.new(5, Array.new(5, 0)) 

と同じ理由があります。コメントに投稿されたように、慣用的に正しいRubyの方法は、5つの異なるarrayオブジェクトの配列に遭遇した問題を防止し、5つの異なるarrayオブジェクトへのポインタを含む単一のアレイを生成する

matrix = Array.new(5){Array.new(5, 0)} 

される作成しますOPによって。 Ruby配列の動作に関する完全なドキュメントはfinely-crafted linkにあります。

0
matrix = [[0]*5]*5 

これを打破するのをしてみましょう:

a = [0]*5 

は5ゼロの配列を作成します。これは整数の配列です。

matrix = [a] * 5 

同じアレイa 5つの参照のアレイを作成します。

もちろん、修正すると他のものは変更されます。それは同じ配列です。

私はRubyを知らないので、間違った用語を修正してください。

+0

これは正しいようです。奇妙なことは、 '[[0] * 5] * 5'と' Array.new(5、Array.new(5、0)) 'の2つの別個の配列があると思いますが、同じオブジェクトを参照してください。 'Array.new(n){Array.new(n、0)}'はブロックを渡すように見えます。 – DaniG2k

1

動作を観察するために対角線を変更する必要はありません。ただ

matrix.map { |row| row.object_id } 
    #=> [70153694327100, 70153694327100, 70153694327100, 
    # 70153694327100, 70153694327100]. 

これがその場合matrixのすべての要素( "行")は、同じオブジェクト、エルゴであることを示していると考えてみましょう

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[1][1] = 1 

を言って、任意の要素を変更しますオブジェクトが変更された場合、matrixのすべての要素が影響を受けます。

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]*5]*5

matrix = Array.new(5, Array.new(5,0)) 

Array::new、expecially "共通落とし穴" を参照してください。)あなたは(@Sebastianノートのように)したい何に相当していますその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]] 
関連する問題