こんにちは!じゃいごテックのあつしです。
今回は多重代入と、shift
・unshift
・pop
・push
メソッドを紹介します。
多重代入
次のように書くと、右辺の配列から左辺の複数の変数に同時に代入を行います。
a, b, c = [1, 2, 3] # 要素数を対応させて代入 p a # > 1 p b # > 2 p c # > 3
配列の要素数が多い場合、余った要素は無視されます。また、配列の要素数が足りない場合、不足分の変数には nil
が代入されます。
a, b = [1, 2, 3] # 右辺3番目の要素(3)が余るので、無視される c, d, e = [4, 5] # e に対応した要素がないので nil が代入される p a # > 1 p b # > 2 p c # > 4 p d # > 5 p e # > nil
左辺に ()
カッコを使うことで入れ子に対応出来ます。
# こう書くと入れ子にアクセスできる (a, b), c = [[1, 2], 3] # こう書くと d に [4, 5] が代入され f には nil が代入される d, e, f = [[4, 5], 6] p a # > 1 p b # > 2 p c # > 3 p d # > [4, 5] p e # > 6 p f # > nil
変数の左に *
があると、そこから後の要素を配列で受け取ります。
# 普通の代入 a = [1, 2, 3, 4, 5] # これも普通の代入と同じ *b = [1, 2, 3, 4, 5] # e に 3番目以降の要素が配列で代入される c, d, *e = [1, 2, 3, 4, 5] p a # > [1, 2, 3, 4, 5] p b # > [1, 2, 3, 4, 5] p c # > 1 p d # > 2 p e # > [3, 4, 5]
*
単体で記述すると、要素を無視します。
# 先頭だけ代入、他は無視 a, * = [1, 2, 3, 4, 5] # 末尾だけ代入、他は無視 *, b = [1, 2, 3, 4, 5] # 先頭と末尾を代入、中間は無視 c, *, d = [1, 2, 3, 4, 5] p a # > 1 p b # > 5 p c # > 1 p d # > 5
慣習的な書き方として、捨てる要素を _
アンダーバーに代入することもあります。
# 1番目の要素を _ に入れておいて使わない(捨てる) _, a, b = [1, 2, 3] p a # > 2 p b # > 3
shift・unshift
shift メソッド
shift(取り出す要素数)
配列の先頭の要素を取り除いてそれを返します。引数が省略された場合は要素を1つ返し、引数が与えられた場合はその個数分の配列を返します。
ary = [1, 2, 3, 4, 5] p ary.shift # > 1 p ary # > [2, 3, 4, 5] p ary.shift(2) # > [2, 3] p ary # > [4, 5]
unshift メソッド
unshift(追加する要素)
引数に与えた要素を引数の末尾から順番に配列の先頭に挿入します。
ary = [1, 2, 3] ary.unshift(0) p ary # > [0, 1, 2, 3] ary.unshift([4, 5]) p ary # > [[4, 5], 0, 1, 2, 3] ary.unshift(*[6, 7]) p ary # > [6, 7, [4, 5], 0, 1, 2, 3] ary.unshift(8, 9) p ary # > [8, 9, 6, 7, [4, 5], 0, 1, 2, 3]
pop・push
pop メソッド
pop(取り出す要素数)
配列の末尾から要素を取り除いてそれを返します。引数が省略された場合は要素を1つ返し、引数が与えられた場合はその個数分の配列を返します。
ary = [1, 2, 3, 4, [5, 6], 7] p ary.pop # > 7 p ary # > [1, 2, 3, 4, [5, 6]] p ary.pop # > [5, 6] p ary # > [1, 2, 3, 4] p ary.pop(2) # > [3, 4] p ary # > [1, 2]
push メソッド
push(追加する要素)
引数に与えた要素を配列の末尾に挿入します。
ary = [1, 2, 3] ary.push(4) p ary # > [1, 2, 3, 4] ary.push([5, 6]) p ary # > [1, 2, 3, 4, [5, 6]] ary.push(*[7, 8]) p ary # > [1, 2, 3, 4, [5, 6], 7, 8] ary.push(9, 10) p ary # > [1, 2, 3, 4, [5, 6], 7, 8, 9, 10]
ここまで覚えられたら複雑な入力データも受け取ることが出来ると思います。
最後にpaiza練習問題で少し複雑な入力データの受け取りをやってみましょう。
paiza練習問題を解いてみる
神経衰弱 (paizaランク B 相当)
※ スキルチェック過去問題セットより
入力データの条件
- 1行目には3つの整数 H, W, Nが入力される
- 続く H 行に、配置されたトランプに書かれた数字が入力される
- 次の行に、記録の長さ L が入力される
- 続く L 行に、捲られたトランプの記録が時系列順で入力される
今回は入力データの受け取りまでやってみますね。(問題の解説はまた今度で・・・)
まずは入力データを変数に代入します。
input1 =<<~"EOS" 2 3 2 1 2 3 2 1 3 5 1 1 2 1 1 1 1 2 1 1 2 2 1 3 2 3 1 2 2 1 EOS input2 =<<~"EOS" 2 5 3 5 8 8 6 3 3 6 3 3 5 8 1 4 2 2 1 3 2 1 2 4 2 3 1 3 1 5 2 5 1 1 2 1 1 2 1 5 2 1 1 2 1 3 EOS
続いて入力データの受け取り部分を作っていきます。
# 行ごとに分割した配列を作る lines = input1.split("\n") # 1行目 H, W, N H, W, N = lines.shift.split.map(&:to_i) # 続くH行に配置されたトランプの数字情報 cards = [] lines.shift(H).each do |line| cards.push(line.split.map(&:to_i)) # 下記のように記述しても同じ動作 # cards << line.split.map(&:to_i) end # 次に L L = lines.shift.to_i # 次の行から最後まで トランプを捲った記録 turn_result = [] lines.each do |line| turn_result.push(line.split.map(&:to_i)) # 下記のように記述しても同じ動作 # turn_result << line.split.map(&:to_i) end
二次元配列の部分をmapの入れ子にして書くと少し短く書けます。
# 行ごとに分割した配列を作る lines = input1.split("\n") # 1行目 H, W, N H, W, N = lines.shift.split.map(&:to_i) # 続くH行に配置されたカードの情報 cards = lines.shift(H).map do |line| line.split.map(&:to_i) end # 次に L L = lines.shift.to_i # 次の行から最後まで 捲られたカードの情報 turn_result = lines.map do |line| line.split.map(&:to_i) end p H # > 2 p W # > 3 p N # > 2 p cards # > [[1, 2, 3], [2, 1, 3]] p turn_result # > [[1, 1, 2, 1], [1, 1, 1, 2], [1, 1, 2, 2], [1, 3, 2, 3], [1, 2, 2, 1]]
今回のまとめ
- 多重代入で複数の変数に同時に代入出来る
- shift, unshift で配列先頭側から要素の出し入れが出来る
- pop, push で配列末尾側から要素の出し入れが出来る