Ruby 知って得する多重代入とmapメソッド

多重代入

多重代入とは、複数の値を同時に代入することです。

a, b = 1, 2
puts a  #=> 1
puts b  #=> 2

多重代入は配列にも使える

特に便利なのが、配列の要素を一度に代入できるところです。

a, b, c = [1, 2, 3]
puts a  #=> 1
puts b  #=> 2
puts c  #=> 3

たとえば、以前紹介した次のコード。

入力値はapple banana orange値は文字列でスペース区切り、最後に改行を含む。

input = gets.split
puts "私は、#{input[0]}#{input[1]}#{input[2]}が好きです。"
#=> 私は、appleとbananaとorangeが好きです。

多重代入を利用すると、次のように書くことができます。

a, b, c = gets.split
puts "私は、#{a}#{b}#{c}が好きです。"
#=> 私は、appleとbananaとorangeが好きです。

見やすくなりました!

最初何が起きているのかよくわからなかったので、順を追って説明してみます。

#"apple banana orange"を受け取って変数inputに代入
input = gets 

#"apple banana orange"を["apple", "banana", "orange"]という配列にして変数fruitsに代入
fruits = input.split

#a, b, c = fruitsは、ここではa, b, c = ["apple", "banana", "orange"]に同じ
a, b, c = fruits

#確認のため変数a, b, cの中身を表示してみる
puts a  #=> apple
puts b  #=> banana
puts c  #=> orange

puts "私は、#{a}#{b}#{c}が好きです。"
#=> 私は、appleとbananaとorangeが好きです。

各要素を数値に変換する

受け取る値を数値として使いたいときはどうしたらよいでしょうか。

(例題)n, m2つの整数が標準入力で渡される。nmの積を出力せよ。入力値は文字列でスペース区切り、最後に改行を含むものとする。

入力値は2 3とします。

n, m = gets.split
puts n * m  #=> エラー!

n, m = gets.splitは、getsで受け取った文字列をsplitによってスペースで分割して配列にした上で、nとmにそれぞれ代入(多重代入)しています。なぜエラーが起きたのでしょうか。pメソッドを使ってnとmの中身を確認してみます。

n, m = gets.split
p n  #=> "2"
p m  #=> "3"

nに2、mに3が代入できていますが、数値ではなく文字列のままなので、"2" * "3"つまり文字列同士の掛け算ができずエラーになったことがわかります。整数に変換するto_iメソッドを使えばいいと思いますが、n.to_im.to_iと一つひとつ書く方法だと、入力値が多い場合に大変です。こんなとき使えるメソッドがあったような…

mapメソッドで配列の各要素を変換

mapは、配列の各要素を処理し、変換後の新しい配列を返すメソッドです。

p [1, 2, 3].map(&:to_s)  #=> ["1", "2", "3"]

上のコードでは、[1, 2, 3]という配列の各数値を、一つずつto_sメソッドで処理し文字列に変換しています。

ちなみにmapを使わず配列に直接to_sを使うと、配列全体を文字列に変換してしまいます。

p [1, 2, 3].to_s  #=> "[1, 2, 3]"

話がそれましたが、mapを使って例題をやっていきます。

いきなり多重代入もmapも全部やると初心者の自分は訳がわからなくなるので、一つずつ処理しながら、適宜変数の中身を確認できるpメソッドを挟みます。

#受け取った文字列をinputという変数に代入
input = gets
p input  #=> "2 3\n"

#splitで"2 3\n"をスペースで分割して配列に入れると同時に末尾の改行"\n"を削除して変数aryに代入
ary = input.split
p ary  #=> ["2", "3"]

#mapメソッドでaryの各要素である文字列を整数に変換し、新しい配列を変数intsに代入
ints = ary.map(&:to_i) 
p ints  #=> [2, 3]

#多重代入。ここでは n, m = [2, 3]に同じ
n, m = ints
p n  #=> 2
p m  #=> 3

#計算して結果を出力
puts n * m  #=> 6  #nもmも整数なのでエラーにならず計算できる

頭の整理ができたところで、まとめて書くと次のようになります。

n, m = gets.split.map(&:to_i)
puts n * m  #=> 6

代入時にchompを入れる例が多いですが、不要な理由については以下の記事をご覧ください。

masuyama13.hatenablog.com