rioRESERVoir

Allajah/Rioの個人ブログ

Rubyの2次元配列で苦戦した話

Rubyで行列の和をとろうとして苦戦した.
f:id:Allajah:20140805153222j:plain
こういうことをしたい.
とりあえず適当にcsvファイルを用意する.

matrixA.csv

1,2,3
4,5,6
7,8,9

matrixB.csv

11,12,13
14,15,16
17,18,19 

csvファイルを読み込んで2次元配列にする.

require 'csv'

matrix_a=CSV.read("./matrixA.csv")
matrix_b=CSV.read("./matrixB.csv")

まずmatirx_aとmatrix_bの各成分を読み込み和を取る.まずここでつまずいた
for文でやろうと思えば

for i in 0..2 do
    for j in 0..2 do
       p matrix_a[i][j].to_i+matrix_b[i][j].to_i
    end
end 

これでいける.実行すると12,14,18,20,22...となり,1行1列目,1行2列目...と加算された結果が表示される.しかしこれではRubyっぽくないし3行3列の行列にしか対応できない.
eachメソッドを使いたい.しかしこの場合はmatrix_aとmatrix_bの2つの要素を同時に読み込んで和を取る必要がある.
調べて見たらzipメソッドとかいうのが使えそう.
zipメソッドを使ってmatrix_aとmatrix_bの成分の和をとってみる.

matrix_a.zip(matrix_b).each do |row_a,row_b| 
    row_a.zip(row_b).each do |column_a,column_b|
        p column_a.to_i+column_b.to_i
    end
end

これでもさっきのfor文でやったのと同じ出力結果が得られた.zipメソッドについてはこのへんに詳しく記載されてる.(http://ref.xaio.jp/ruby/classes/array/zip)

つぎはこの計算結果を二次元配列に格納する.
まず空の二次元配列を生成する.

matrix_c=Array.new.map{Array.new} 

数値を格納するにはこんな感じ.pushメソッドを使う

i=0
matrix_a.zip(matrix_b).each do |row_a,row_b| 
    matrix_c.push Array.new 
    row_a.zip(row_b).each do |column_a,column_b|
        matrix_c[i].push column_a.to_i+column_b.to_i
    end
    i+=1
end

空の二次元配列matrix_cに3行目で空の配列をpushする.その配列に5行目で加算した成分をpushする.
i=0は行列の1行目,i+=1で1行下にずらしてる.

最終的なソース

require 'csv'

matrix_a=CSV.read("./matrixA.csv")
matrix_b=CSV.read("./matrixB.csv")

matrix_c=Array.new.map{Array.new} #create square matrix for operation result
i=0
matrix_a.zip(matrix_b).each do |row_a,row_b| 
    matrix_c.push Array.new 
    row_a.zip(row_b).each do |column_a,column_b|
        matrix_c[i].push column_a.to_i+column_b.to_i
    end
    i+=1
end
p matrix_c

実行結果

[[12, 14, 16], [18, 20, 22], [24, 26, 28]]


あとは差と積も作って一つのファイルにまとめてメソッド化したい.
csvに吐き出せるようにしてたの忘れてたからそれも.
ブログ書くのもうちょっと時間かけられれば,後で見た時もう少しわかりやすくなる気がする…

ツッコミ等あったらご指摘ください.

追記
Matrixライブラリというのがあるらしい