こちらの問題を解いている時にハマったのでその備忘録です。
入力された行列の転置行列を求めよ
練習問題を毎日解いている背景はこちら。
考えた回答
最初に作ったのはこちらの回答。配列nをlにコピーしておいて、要素1つ1つの行と列を逆にして代入していく仕組み。
require 'minitest/autorun' def tenchi(n) l = n n.length.times do |row| n.length.times do |col| l[row][col] = n[col][row] end end l end class TenchiTest < Minitest::Test def test_tenchi assert_equal [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]].transpose , tenchi([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]) end end
しかし、これだとテストがうまく通らない。
記述しているロジックを紙に書いてみたりしたが、特に問題がないように思っていた。。
気づき
ロジックの考え方自体には問題がないのであれば、l = n
のあたりに問題があるのではないかと、Rubyにおける変数の扱いについて調べてみた。
そこで分かったのがタイトルの通り「Rubyの変数はラベル」であること。
この記事が一番わかりやすかった。 gam0022.net
変数はそれ自体が一つの箱のようなイメージをしていたが、そうではなく、オブジェクトへの参照を示しているだけである。
するとどういうことが起きるかは以下が分かりやすい。
n = i
を実施すると、iのさす配列を新しく作るのではなく、同じ配列に新しくnというラベルを付与する、という操作を行ったことになる。
つまり、同じオブジェクトを指しているので、iの値を変更した時に、同時にnの値も変更になることに注意が必要だ。
> i = [1, 2, 3] > n = i > n => [1, 2, 3] > i[0] = 10 > i => [10, 2, 3] > n => [10, 2, 3]
回答
その上で、最初に作成した回答を見てみると、上記のように、i = n
で同じオブジェクトを参照してしまっていることになる。
ここの部分を、新規で空の配列を作るように変えてあげる。
l = Array.new(4).map{Array.new(4)}
するとあくまで新しい配列に値を代入していくだけなので、無事テストも通ることが確認できる。