Edited at

Ruby で競技プログラミングをするときのまとめ(多次元配列編)

More than 1 year has passed since last update.


  • リクエストに応じて追記していきます。

  • 環境は AtCoder を想定しています。なお AtCoder の Ruby のバージョンは 2018年10月現在 2.3.3 です。


入力について


入力が地図のパターン

$H$, $W$ は整数

$c_{i,j}$ はなんらかの文字


$H \quad W$

$c_{1,1}c_{1,2}...c_{1,W}$

$c_{2,1}c_{2,2}...c_{2,W}$

$:$

$c_{H,1}c_{H,2}...c_{H,W}$


文字列の配列にしたいとき

H, W = gets.split.map(&:to_i)

c = H.times.map { gets.chomp }

1文字ずつの二次元配列にしたいとき

H, W = gets.split.map(&:to_i)

c = H.times.map { gets.chomp.chars }


入力が数の二次元配列のパターン

$H$, $W$ は整数

$a_{i,j}$ は整数


$H \quad W$

$a_{1,1} \quad a_{1,2} \quad ... \quad a_{1,W}$

$a_{2,1} \quad a_{2,2} \quad ... \quad a_{2,W}$

$...$

$a_{H,1} \quad a_{H,2} \quad ... \quad a_{H,W}$


H, W = gets.split.map(&:to_i)

a = H.times.map { gets.split.map(&:to_i) }


入力が幅と高さのみで、二次元配列を自分で作るパターン

$H$, $W$ は整数


$H \quad W$


H, W = gets.split.map(&:to_i)

a = H.times.map {|i|
W.times.map {|j|
# i, j による初期値
}
}


処理について


文字列の配列の各文字ごとに何かしたいとき

文字だけでいいとき

c.each {|line|

line.chars {|ch|
# ch の処理
}
}

インデックスが必要なとき

H.times {|i|

W.times {|j|
# c[i][j] の処理
}
}


二次元配列の各要素ごとに何かしたいとき

要素だけでいいとき

a.each {|row|

row.each {|elem|
# elem の処理
}
}

インデックスが必要なとき

H.times {|i|

W.times {|j|
# a[i][j] の処理
}
}

両方(HW がわかっているなら上で十分)

a.each_with_index {|row, i|

row.each_with_index {|elem, j|
# i, j, elem の処理
}
}


地図とかで上下左右を参照するとき

H.times {|i|

W.times {|j|
[
[-1, 0], # 上
[ 1, 0], # 下
[ 0, -1], # 左
[ 0, 1], # 右
].each {|di, dj|
if 0<=i+di && i+di<H && 0<=j+dj && j+dj<W
# c[i + di][j + dj] の処理
else
# 範囲外のときの処理
end
}
# c[i][j] の処理
}
}


地図とかで斜めも含め八方を参照するとき

H.times {|i|

W.times {|j|
(-1..1).each {|di|
(-1..1).each {|dj|
if di==0 && dj==0
# c[i][j] の処理
elsif 0<=i+di && i+di<H && 0<=j+dj && j+dj<W
# c[i + di][j + dj] の処理
else
# 範囲外のときの処理
end
}
}
# c[i][j] の処理
}
}


インデックスについて


注意1:範囲外のアクセス(size 以上のとき)

a[i][j] のようにアクセスしたとき、ia.size 以上であると a[i]nil を返し、そのまま [j] でアクセスしてエラーを起こします。

undefined method `[]' for nil:NilClass (NoMethodError)

対処法として、i の大きさを確認するか、a[i]nil でないことを確認しましょう。


注意2:範囲外のアクセス(0 未満のとき)

注意1では触れませんでしたが、Ruby では 配列のインデックスに負数を指定することができます。

-1 が一番最後で、後ろから -1, -2, ... という具合で指定できます。

これは便利なときと不便なときがあって、地図が上下左右でつながっている(ドラクエみたいな)問題では便利ですが、そうでないときは不便です。

不要なときは i の大きさを確認しましょう。a[i]nil であるとは限らなくなるので、 nil チェックは使えません。


出力について

c が文字列の配列のとき

puts c

c が文字の二次元配列のとき

puts c.map(&:join)

a が数値の二次元配列で、スペース区切りで出力するとき

puts a.map {|line| line.join(" ") }

または

a.each {|line| puts line.join(" ") }