morimorihogeです。そとがさむい。
たまには初心者向けの記事を書いてみようということで、Rubyの配列であるArrayクラスについて、基本的な部分に絞った内容を書いてみようと思います。PHP等の他言語からRubyを勉強している人なんかには参考になるのではないかと思います。
※超初心者向けです。確認環境は2.4.0準拠ですが1.9.3以降のそこそこ最近のRubyであればほとんど問題なく利用できると思います。
基本的には公式のArrayドキュメント に書いてあることばかりですが、リファレンス形式だと読みにくい、という人はどうぞ。
なお、引用サンプルではpry の出力結果を出していますが、これはIRBでも同じことができます。手元で動かしてみたい方はrubyが入っていればとりあえずirb
して以下を追いかけてもらうと良いでしょう。
Arrayの初期化
RubyにおけるArrayは、リテラルを使って初期化できます。空配列であれば
arr_var = []
で良いですし、明示的にArray.newを使って
arr_var = Array.new
とすることもできます。
RubyのArrayはPHP等と同じように、中にどんなオブジェクトも要素として持つことができますので、
[1, "piyo", nil, nil]
といったArrayも定義可能です。また、Rubyらしい初期化方式だと、Array.newにブロックを渡して
[3] pry(main)> Array.new(5) {|index| "hoge_#{index}"}
=> ["hoge_0", "hoge_1", "hoge_2", "hoge_3", "hoge_4"]
みたいなこともできます。
Arrayの要素アクセス
要素へのアクセスは、他の言語でも一般的な添字を使った
arr_var[1]
といったアクセス(添字は0番目から始まる)もありますし、#fetch
メソッドを使い
arr_var.fetch(1)
としても良いです。通常は添字アクセスだけ覚えていれば良いように思いますが、#fetch
は第二引数に値が見つからなかった場合のデフォルト値指定ができるため、
[12] pry(main)> arr_var[10000]
=> nil
[13] pry(main)> arr_var.fetch(10000, 0)
=> 0
という感じで指定した添字の値がない場合にnil以外を受け取りたい、といったときに覚えておくと便利です。
また、Rubyらしいアクセス方式として、添字にRangeオブジェクト(n..m
)を渡すことによって部分Arrayを取り出せます。n番目の要素からm番目の要素まで取り出す感じですね。
[60] pry(main)> arr_var = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
[61] pry(main)> arr_var[2..3]
=> [3, 4]
Arrayの大きさ取得 #size
#length
Arrayの要素数を取得するには#size
または#length
を使います。最大の添字番号ではないので注意です。
[53] pry(main)> arr_var = [1,2,3]
=> [1, 2, 3]
[54] pry(main)> arr_var.size
=> 3
[55] pry(main)> arr_var.length
=> 3
Arrayの要素に対する繰り返し
どんな入門書にも必ず載っている#each
とブロックを使えば良いですね。Rubyではcollection(集合)オブジェクトの中身を順番に取り出したければ基本#each
だと思っていて良いです。
Rubyにfor文
は構文としてはありますが、ほとんど使われません。他言語から来た人が一番違和感を覚える所かもしれませんが、ブロックを使った記法に慣れるためにもforは使わず#each
を使うようにしていくのが良いと思います。
中括弧を使ったブロックの書き方では
arr_var.each{|val| puts "value: #{val}"}
do-end
を使った書き方であれば
arr_var.each do |val|
puts "value: #{val}"
end
とすれば良いです。上記二つは全く同じ意味になりますが、Ruby Style GuideというRubyの好ましい書き方まとめ に沿うのであれば、ブロックの中身が1行で終わるなら中括弧記法、2行以上あるならdo-end
記法となります。
とりあえず動けばいいや、という話であればどちらでも構いませんが、よりRubyらしい書き方、美しい(他人が読みやすいとされる)コードを目指すのであれば少しずつ追いかけていくと良いと思います。
Arrayの要素削除
Arrayから特定の要素を削除したい場合には#delete
または#delete_at
を使います。
#delete
は引数と==マッチする要素全てを削除します。添字番号を指定して削除するのは#delete_at
です。間違えると悲しいことになるので気をつけましょう。
[14] pry(main)> arr_var = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
[15] pry(main)> arr_var.delete(4)
=> 4
[16] pry(main)> arr_var
=> [1, 2, 3, 5]
[17] pry(main)> arr_var = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
[18] pry(main)> arr_var.delete_at(4)
=> 5
[19] pry(main)> arr_var
=> [1, 2, 3, 4]
Ruby的なメソッドとしては#delete_if
があります。これは要素を順番にブロック内で評価し、ブロックの評価結果(最後に評価された式)がtrueになった要素を削除します。
他の言語だとforやforeachループを書いて削除していく処理を、組み込みメソッドで書けるのがシンプルで良いですね。
[20] pry(main)> arr_var = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
[21] pry(main)> arr_var.delete_if{|var| 2 < var && var < 5}
=> [1, 2, 5]
[22] pry(main)> arr_var
=> [1, 2, 5]
Arrayのソート(並べ替え)
Arrayをソートしたい場合には#sort
を使います。
[23] pry(main)> arr_var = [-1,3,0,-10,1]
=> [-1, 3, 0, -10, 1]
[24] pry(main)> arr_var.sort
=> [-10, -1, 0, 1, 3]
正しいソート結果を得たい場合には、要素の型を揃える必要があります。文字列と数値など、相互に比較できないものが混じるとエラーになります。
[25] pry(main)> arr_var = [-1,"5",2,"0",-10]
=> [-1, "5", 2, "0", -10]
[26] pry(main)> arr_var.sort
ArgumentError: comparison of Integer with String failed
from (pry):26:in `sort'
しかし、こんなときも#sort
メソッドのブロックにオブジェクトの比較条件を渡してやることで、ソートさせることが可能です。
以下は#to_i
メソッドを使うことで文字列も数値も全て数値に変換した上で比較するようにした例です。
[28] pry(main)> arr_var.sort{|a,b| a.to_i <=> b.to_i}
=> [-10, -1, "0", 2, "5"]
なお、逆順にしたければ#reverse
を使えば良いです。逆順に#each
したければ#each
の代わりに#reverse_each
を使うことができます。
[31] pry(main)> arr_var
=> [-1, "5", 2, "0", -10]
[32] pry(main)> arr_var.reverse
=> [-10, "0", 2, "5", -1]
スタックアクセス
Arrayをスタック的なデータ置き場として使いたい場合は#push
、#pop
を使えば良いです。要素が無い状態で#pop
すると、nilが返るようになっています。
[34] pry(main)> arr_var = []
=> []
[35] pry(main)> arr_var.push 'a'
=> ["a"]
[36] pry(main)> arr_var.push 'b'
=> ["a", "b"]
[37] pry(main)> arr_var.push 'c'
=> ["a", "b", "c"]
[38] pry(main)> arr_var.pop
=> "c"
[39] pry(main)> arr_var.pop
=> "b"
[40] pry(main)> arr_var.pop
=> "a"
[41] pry(main)> arr_var.pop
=> nil
その他よく使われる・便利なメソッド達
ここまでは他の言語でも一般的に実装されている機能ですが、ここからはあまり他言語では見ないメソッドを紹介してみます。
要素追加 <<
<<
を使って要素の追加ができます。#push
と違い同時に1要素しか追加できませんが、Arrayに新しく要素を追加する、という意味合いでわかりやすいためか、Rubyではよく使われます。
[42] pry(main)> arr_var = []
=> []
[43] pry(main)> arr_var << 1
=> [1]
[44] pry(main)> arr_var << 2
=> [1, 2]
[45] pry(main)> arr_var << 3
=> [1, 2, 3]
1番目の要素を返す #first
、最後の要素を返す #last
Arrayの先頭の要素を取るには添字アクセスで[0]
を取ってももちろん良いのですが、最初と最後の要素については#first
と#last
によってアクセスすることができます(Rails環境だとActiveSupportが入るため、#second
なんかも使えますがRuby標準ではこの二つのみ)。
[46] pry(main)> arr_var = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
[47] pry(main)> arr_var.first
=> 1
[48] pry(main)> arr_var.last
=> 5
また、Arrayの末尾要素は「後ろから数えて1番目」なので添字[-1]
でも取得することが可能です。
[50] pry(main)> arr_var[-1]
=> 5
入れ子になったArrayを全部展開する#flatten
入れ子になっているArrayをフラットなArrayに解きほぐして展開します。これは実際の処理結果を見るのが早いと思います。
[51] pry(main)> arr_var = [[1,2,3], 4,[5,[6,[7,8],9]],10]
=> [[1, 2, 3], 4, [5, [6, [7, 8], 9]], 10]
[52] pry(main)> arr_var.flatten
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
どんな時に使うかこれだけだとピンと来ないかもしれませんが、例えば公開APIを利用していて入れ子になったデータ構造を取得したときに、階層関係なく全ての要素について処理したいといった場合、何階層あるのかよく分からないデータをとりあえず処理したいといった場合にあると嬉しいメソッドです。
空かどうかを調べる#empty?
Arrayの中身が空かどうかを調べるには、要素数が0であるかを#length
で調べても良いのですが、Rubyはより自然言語的な書き方が好まれることから#empty?
を使うことが多いです。この辺りは文化的なものもあるので、他言語から移行してくる人には違和感があるかもしれませんが、こういうものだと思って慣れましょう。
[1] pry(main)> arr_var = [1,2]
=> [1, 2]
[2] pry(main)> arr_var.empty?
=> false
[3] pry(main)> arr_var = []
=> []
[4] pry(main)> arr_var.empty?
=> true
まとめ
そんなわけで、公式のArrayドキュメント からRubyを使う上でよく使うメソッド群を紹介してみました。
まだ紹介していないメソッドも多数ありますが、とりあえずここに挙げたものが使えれば他言語から移行してきた人でも最低限やりたいことはできるのではないかと思います。