Ruby プログラミング

[Ruby] 標準入力からのデータ取得3

stdin_3

こんにちは!じゃいごテックのあつしです。

今回は多重代入と、shiftunshiftpoppushメソッドを紹介します。

多重代入

次のように書くと、右辺の配列から左辺の複数の変数に同時に代入を行います。

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 で配列末尾側から要素の出し入れが出来る
これで標準入力はバッチリですね!今度は問題にも挑戦してみましょう!

【PR】Ruby学習でお世話になった本




【PR】アルゴリズム学習でお世話になった本


アルゴリズム関連の技術書は大抵C/C++で書かれていますが、ある程度プログラムが出来れば、処理の流れは理解することが出来ます。






通称: 螺旋本。C++で解説されています。AOJ(Aizu Online Judge)を運営している会津大学の渡辺准教授が書いた本です。データ構造や計算量の内容から丁寧に書いてありますのでアルゴリズム学習の最初の参考書としてオススメです。







通称: 蟻本。C++で解説されています。競技プログラミング中級者の定番書と言われていて、競技プログラミングで利用できる色々なアルゴリズムを学ぶことが出来ます。かなり高度な内容も含まれているので1冊分を完全に理解するのにはかなりの時間がかかりそうですが、手元に置いて何度も読み返しています。







通称: チーター本。C#, C++, JAVAでTopcoderの問題を解説しています。初心者~中級者向けに書かれているので解説が非常に丁寧です。







Python3でアルゴリズムを解説している本です。講義スタイルの本で、図やフローチャートを使ってアルゴリズムとデータ構造についてしっかりと説明されています。代わりにコードは少なめです。Pythonコードが読めなくても十分理解できると思います。


-Ruby, プログラミング
-, ,

© 2024 じゃいごテック