STUDY MEMO

学習のメモ書き

<Ruby> 配列とメソッド

配列と要素

配列とはArrayオブジェクトまたは配列オブジェクトと呼ばれ、内部にStringやIntegerなどのオブジェクトを入れることができるオブジェクトのこと。
Image from Gyazo クラスの継承は以下の通り。

BasicObject > Kernel > Object > Enumerable > Array
fruits = ['りんご', 'みかん', 'さくらんぼ']
p fruits  #  => ["りんご", "みかん", "さくらんぼ"]

配列を代入する変数は複数形にする慣習がある。


要素

配列の中に入れられているオブジェクトは要素と呼ばれる。
要素の取り出しはfirst、lastのメソッドを使う場合と要素を指定して取り出す場合がある。
要素は先頭が0から始まっていて、0, 1, 2...と続く。

fruits = ['りんご', 'みかん', 'さくらんぼ']
p fruits.first  #  => "りんご"
p fruits.last  #  => "さくらんぼ"
p fruits[0]  #  => "りんご"
p fruits[1]  #  => "みかん"
p fruits[2]  #  => "さくらんぼ"

要素指定はマイナスを使うこともできる。
この場合は後ろから-1,-2,...と続く。

fruits = ['りんご', 'みかん', 'さくらんぼ']
p fruits[-1]  #  => "さくらんぼ"  ( = p fruits[2] )
p fruits[-2]   #  => "みかん" ( = p fruits[1] )
p fruits[-3]  #  => "りんご" ( = p fruits[0] )

オブジェクトの入っていない要素を指定した場合、nilが返る。

fruits = ['りんご', 'みかん', 'さくらんぼ']
p fruits[-4]  #  => nil
p fruits[3]  #  => nil


配列のメソッド

要素の追加

Arrayクラスのインスタンスメソッドである以下が使用される。


push, appendメソッド

指定されたオブジェクトを順番に配列の末尾に追加され、引数は複数指定できる。

fruits = ['りんご', 'みかん' ]
p fruits  #  =>  ["りんご", "みかん"]
fruits.push('さくらんぼ')
p fruits  #  =>  ["りんご", "みかん", "さくらんぼ"]
fruits.append('ぶどう')
p fruits  #  =>  ["りんご", "みかん", "さくらんぼ", "ぶどう"]


<<メソッド

指定された要素を自身の末尾に破壊的(破壊的メソッドについては後述)に追加。
引数は一つしか指定できない。

fruits = ['りんご', 'みかん' ]
p fruits
fruits << 'かぼす'
p fruits


破壊的メソッドのため、自身であるselfを返すので、連続してメソッドを記述することができる。

fruits = ['りんご', 'みかん' ]
p fruits  #  =>  ["りんご", "みかん"]
p fruits << 'トマト' << 'しじみ'  #  =>  ["りんご", "みかん", "トマト", "しじみ"]


unshiftメソッド、prependメソッド

指定されたオブジェクトを引数の後ろから配列の先頭に挿入し、引数は複数指定できる。

fruits = ['りんご', 'みかん' ]
p fruits  #  =>  ["りんご", "みかん"]
fruits.unshift('いちご')
p fruits  #  =>  ["いちご", "りんご", "みかん"]
fruits.prepend('パイナップル')
p fruits  #  =>  ["パイナップル", "いちご", "りんご", "みかん"]


要素の削除

pop

最後の要素を削除し、返す値は取り除いた要素。

fruits = ['りんご', 'みかん', 'ぶどう' ]

p fruits  #  =>  ["りんご", "みかん", "ぶどう"]
p fruits.pop  #  =>  "ぶどう"
p fruits  #  =>  ["りんご", "みかん"]


shift

先頭の要素を削除し、返す値は取り除いた要素。

fruits = ['りんご', 'みかん', 'ぶどう' ]

p fruits  #  =>  ["りんご", "みかん", "ぶどう"]
p fruits.shift  #  =>  "りんご"
p fruits  #  =>  ["みかん", "ぶどう"]

配列の結合

+メソッド

それぞれオブジェクトを繋げた配列を生成する。

fruits = ['りんご', 'みかん', 'ぶどう' ]
vegtables = ['玉ねぎ', 'ほうれん草']
p fruits + vegtables  #  =>  ["りんご", "みかん", "ぶどう", "玉ねぎ", "ほうれん草"]


配列の引き算

-メソッド

元の配列から引く側の配列との重複する要素を削除する。

fruits = ['りんご', 'みかん', 'ぶどう', 'りんご', 'みかん', 'ぶどう']
apples = ['りんご']
p fruits - apples  #  =>  ["みかん", "ぶどう", "みかん", "ぶどう"]


配列の繰り返し処理

each

配列の要素を全て表示することができる。
|(パイプ)に挟まれたものは変数で、この変数に配列の各要素が代入され、繰り返し実行される。
慣例的に単数形が入る。

fruits = ['りんご', 'みかん', 'ぶどう']

# do ... endを使用する場合
fruits.each do |f|
  p f
end

# 一行で記載した場合
fruits.each { |f| p f }

# 結果
"りんご"
"みかん"
"ぶどう"


繰り返しを途中で終了する break

breakと条件式を組み合わせることで繰り返しを途中で終了することができる。

fruits = ['りんご', 'みかん', 'ぶどう']

fruits.each do |f|
  break if f == 'みかん' 
  p f
end

# 結果
"りんご"


次の要素の繰り返しへ進む next

nextと条件式を組み合わせることで指定した繰り返しの処理を終了して次の繰り返しに進めることができる。

fruits = ['りんご', 'みかん', 'ぶどう']

fruits.each do |f|
  next if f == 'みかん' 
  p f
end

# 結果
"りんご"
"ぶどう"


範囲を指定する range

rangeは範囲オブジェクトであり、以下のような書き方ができる。

25..35  # 25以上35以下
25...36  # 25以上36未満

Range.new(25, 35)
=> 25..35

これをeachに使用すると、以下のようになる。

(1..3).each do |a|
  p a
end

# 結果
1
2
3


素数を数える

size,lengthメソッド

配列の長さをinteger型で返し、空のときは 0 を返す。

numbers = [1,2,3,4,5]
p numbers.size  #  =>  5
p numbers.length  #  =>  5

zero = []
p zero.size  #  =>  0
p zero.length  #  =>  0


要素の合計

sumメソッド

要素の合計を返す。
sizeと組み合わせると平均を出すことができる。

numbers = [1,2,3,4,5]
p numbers.sum  #  =>  15
p numbers.sum / numbers.size  #  =>  3

# 少数の場合はto_fを使用してメソッドチェーンで計算
floats = [1, 1, 2]  #  =>  sizeは4, sumは3なので平均は少数になる
p floats.sum / floats.size  #  =>  1
p floats.sum.to_f / floats.size.to_f  #  =>  1.3333333333333333

sumとsizeメソッドの戻り値はInteger型のため、Integer型のインスタンスメソッドであるto_fが使用できるため、上記のメソッドチェーンができる。


重複を削除

uniqメソッドとuniq!メソッド

配列の中での重複を削除した新しい配列を返す。
破壊的メソッドのuniq!は、配列を新しくつくらず、自身の配列を作り直す。
そのため使い分けとしては元の配列の情報を残したいかどうかで分ける。

fruits = ['いちご', 'ぶどう', 'バナナ', 'いちご']

p fruits.uniq  #  =>  ["いちご", "ぶどう", "バナナ"]
p fruits  #  =>  ["いちご", "ぶどう", "バナナ", "いちご"]
p fruits.uniq!  #  =>  ["いちご", "ぶどう", "バナナ"]
p fruits  #  =>  ["いちご", "ぶどう", "バナナ"]

# オブジェクトIDを調べる
p fruits.uniq.object_id  #  =>  70247881844820  
p fruits.object_id  #  =>  70247881844860  object_idが違う = 参照先が異なる

p fruits.uniq!.object_id  #  =>  70247881844860
p fruits.object_id  #  =>  70247881844860  object_idが同じ = 参照先が同じ

uniqメソッドはeachメソッド同様ブロックを渡すことができる。

numbers = ['1', 1, 3, 2, '3']

p numbers.uniq { |n| n.to_i }  #  =>  ["1", 3, 2]

上の例では配列の要素を手前から順に取り出してInteger型に変換していて、それを最後uniqで重複削除している。
重複している場合、最初に記載された要素が残る。
<流れ>
{ |n| ... } : numbersの要素を順に変数nに代入

n.to_i -> 変数nに入った要素をInteger型に変換

ブロックの処理のuniqに返し、numbers.uniqで重複した要素を削除


ランダムに要素を取り出す

sampleメソッド

要素を1個ランダムに返し、引数で指定すると配列内に存在する要素数を越えない範囲で取り出すことができる。

fruits = ['みかん','バナナ','いちご','りんご']

p fruits.sample  #  =>  "りんご"
p fruits.sample  #  =>  "みかん"
p fruits.sample(3)  #  =>  ["いちご", "りんご", "みかん"]


要素をランダムにシャッフルする

shuffleソッド

要素をランダムにシャッフルして,その結果返す。

fruits = ['みかん','バナナ','いちご','りんご']
p fruits.shuffle  #  =>  ["みかん", "バナナ", "りんご", "いちご"]
p fruits.shuffle  #  =>  ["いちご", "みかん", "りんご", "バナナ"]


要素をソートする

sort, sort!メソッド

配列の要素をソートした配列を返す。
破壊的メソッドsort!は前述のように自分自身の配列を作り直したものを返す。
数字の場合は昇順(小さい順)に、文字列の場合はa, b, c...順になる。

ソートとは?
データを一定の基準で並べかえることをソートという。

numbers = [4,3,6,2,5,1]

p numbers.sort  #  =>  [1, 2, 3, 4, 5, 6]
p numbers  #  =>  [4, 3, 6, 2, 5, 1]
p numbers.sort!  #  =>  [1, 2, 3, 4, 5, 6]
p numbers  #  =>  [1, 2, 3, 4, 5, 6]

sortの戻り値は配列のため、arrayクラスのメソッドが使用できる。
reverseメソッドをメソッドチェーンとして使用すると降順にすることができる。

numbers = [4,3,6,2,5,1]

p numbers.sort  #  =>  [1, 2, 3, 4, 5, 6]
p numbers.sort.reverse  #  =>  [6, 5, 4, 3, 2, 1]


要素の連結

joinメソッド

要素に、引数の文字列を間に挟んで連結した文字列を返す。
間に挟むので、最後の要素の後ろに引数の文字列は入らない。

fruits = ['りんご', 'みかん', 'ぶどう' ]
p fruits.join('と、')  #  =>  "りんごと、みかんと、ぶどう"


文字列を分割して配列にする

splitメソッド

Stringクラスのインスタンスメソッド。
文字列を引数に指定した文字列で分割する。

dish_count = '1まい、2まい、3まい'
p dish_count.split('')  #  =>  ["1まい", "2まい", "3まい"]


配列の各要素を変換

map, collectメソッド

各要素に対してブロック処理をして、その結果でできた要素による新しい配列を返す。
よく似たメソッドのeachがあるが、以下のような違いがある。

eachメソッド→各要素に対して処理を行い、その結果が目的であること
mapメソッド→各要素に対して処理を行い、その結果の配列の取得が目的であること

# do~endを使った場合
result = [1000, 5000, 10000].map do |x|
  "#{x}円札"
end
p result

# {}を使った場合
result = [1000, 5000, 10000].map{|x| "#{x}円札" }
p result

↓結果
["1000円札", "5000円札", "10000円札"]


各要素に対して特定のメソッドを呼び出すだけの場合は、 1. メソッドをシンボル(:を先頭につける)にする
2. その前に&をつける
これだけで要素を代入する変数の記載を省略することができる。

# 要素を代入する変数を記載する場合
result = ["123", "456", "789"].map{|n| n.reverse }
p result

# &とメソッドシンボルを使用する場合
result = ["123", "456", "789"].map(&:reverse)
p result

# 結果
["321", "654", "987"]


参考文献

ゼロからわかる Ruby 超入門 (かんたんIT基礎講座) | 五十嵐 邦明, 松岡 浩平 |本 | 通販 | Amazon

class Array (Ruby 3.0.0 リファレンスマニュアル)

class Range (Ruby 3.0.0 リファレンスマニュアル)

制御構造 (Ruby 3.0.0 リファレンスマニュアル)

Integer#to_f (Ruby 3.0.0 リファレンスマニュアル)

最速Rubyリファレンスマニュアル検索! | るりまサーチ