もくじ
スポンサーリンク
Rubyの配列の基本性質
配列が持つのは参照値
Rubyの配列というのは、複数のオブジェクトへの参照値を並べて管理する為のもの。
値そのものではなく、参照値を並べて保持している。
型は何でもあり
1つの配列に文字列でも数値でもオブジェクトでも何でも入れられる。というかRubyでは文字列も数値もオブジェクトなので、要は何らかのオブジェクトへの参照値を並べて保持しているだけ。
配列自体もオブジェクト
配列そのものもオブジェクトであり、Arrayクラスで定義されている。
つまり配列ってのはArrayインスタンスのこと。
スポンサーリンク
配列の作り方
[ ]を使う
1 2 | array1 = ["foo", "var", "baz"] array2 = [1, 2, 3] |
最も簡単なやり方です。コンマで区切るだけ。
普通に配列を用意したい場合は、このやり方を使えばいいと思います。
Arrayクラスのクラス関数を使う
Arrayクラスのクラス関数であるnewを使うことで、Arrayインスタンス(要は配列)を作ることも出来ます。
Array.new(size = 0, obj = nil)
第一引数 要素数 default: 0
第二引数 すべての要素 default: nil
このやり方の場合、全ての要素が同じになるので、初期状態から何らかの値を入れたい場合は使いにくいです。もちろん同じ要素(値)ではありますが、参照しているオブジェクトはそれぞれ違うので、後から各要素の値を上書きして違うのに変えることはできます。
1 2 3 4 5 6 7 8 | array1 = Array.new() p array1 #=> [] array2 = Array.new(3) p array2 #=> [nil, nil, nil] array3 = Array.new(3, "foo") p array3 #=> ["foo", "foo", "foo"] |
このnew関数を使うやり方はもう一つあります。こっちの方が使いようによっては便利だと思います。
Array.new(size = 0){|idx| block}
第一引数 要素数 default: 0
idx 要素ごとに0から順に整数が入る
block 各要素 idxを使った式を書くことで数列を定義する
これを使えば、数列みたいな配列を一発で作ることができます。
1 2 3 4 5 | array1 = Array.new(10){|i| i} p array1 #=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] array2 = Array.new(10) {|i| 2*(i+1)} p array2 #=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] |
配列のインデックス
インデックスは0から順に普通に指定することが出来ます。
1 2 3 4 5 | array1 = ["foo", "var", "baz"] p array1[1] #=> "var" array1[1] = "foo" p array1 #=> ["foo", "foo", "baz"] |
後ろから指定したい時はマイナスを使えます。一番後ろの要素が「-1」です。
1 2 | array1 = ["foo", "var", "baz"] p array1[-2] #=> "var" |
指定するインデックスが、要素数を超えてもエラーにはならず、要素が追加されます。
1 2 3 | array1 = ["あ", "い", "う"] array1[3] = "え" #4番目に"え"を追加 p array1 #=> ["あ", "い", "う", "え"] |
間を飛ばして要素を追加することもできます。その場合、間の要素はnilで埋められます。
1 2 3 | array1 = ["あ", "い", "う"] array1[4] = "お" #4番目を飛ばして5番目に"お"を追加 p array1 #=> ["あ", "い", "う", nil, "お"] |
ただし、マイナスを使って後ろから指定する場合は、要素数を超える数を指定するとnilとなり、そこに代入しようとするとIndexErrorでアウトです。
1 2 3 | array1 = ["あ", "い", "う"] p array1[-4] #=> nil p array1[-4] = "あ" #IndexError |
「..」を使って複数の要素を指定することも出来ます。
1 2 | array1 = ["あ", "い", "う", "え", "お"] p array1[1..3] #=> ["い", "う", "え"] |
ただし複数の要素を指定して、値(1つの要素)を代入すると、その複数の要素がギュッと1つになってしまう(要素数が減る)ので注意。
1 2 3 | array1 = ["あ", "い", "う", "え", "お"] array1[1..3] = "か" p array1 #=> ["あ", "か", "お"] |
「…」なら後ろ側で指定した要素を含まないように指定することになります。
1 2 | array1 = ["あ", "い", "う", "え", "お"] p array1[1...3] #=> ["い", "う"] |
「,」区切りで[start, length]という指定の仕方も出来ます。
1 2 | array1 = ["あ", "い", "う", "え", "お"] p array1[1,2] #=> ["い", "う"] |
lengthの値が要素数を超えても特に問題なく、最後の要素までを指定したことになります。
1 2 | array1 = ["あ", "い", "う", "え", "お"] p array1[1, 10] #=> ["い", "う", "え", "お"] |
lengthに0を指定することで、挿入することも出来ます。
1 2 3 | array1 = ["あ", "い", "う", "え", "お"] array1[1, 0] = "か" p array1 #=> ["あ", "か", "い", "う", "え", "お"] |
Arrayクラスの代表的なインスタンスメソッド
配列の要素数を返すlength, size
lengthとsizeは全く同じ関数みたいです。言語によっていろいろなので両方定義しているのかな?
1 2 3 | array1 = ["foo", "var", "baz"] puts array1.length #=> 3 puts array1.size #=> 3 |
配列が空かどうかを調べるempty?
その配列が空(要素数が0)なら、trueを返します。1つでも要素があればfalseを返します。
※ちなみに関数名の後ろにつく「?」はわざわざ付けているわけでも、何らかの文法というわけでもなく、単に関数名の一部なだけです。Rubyではbooleanを返す関数には関数名の最後に「?」を付けるのが名付けのルールです。
1 2 3 4 5 | array1 = ["foo", "var", "baz"] p array1.empty? #=> false array2 = Array.new(0) p array2.empty? #=> true |
その要素が含まれているかどうかを調べるinclude?
配列の中に、その要素が含まれているかどうかを調べられるのが、include?関数。
array.include?(obj)
配列arrayの中にobjが含まれていればtrueを返し、含まれていなければfalseを返す
引数に、含まれているかどうか調べたいオブジェクトを入れます。
1 2 3 4 | array1 = ["foo", "var", "baz"] p array1.include?("baz") #=> true p array1.include?("baa") #=> false |
配列の要素数だけ繰り返し処理をするeach
each関数を使えば、面倒なfor文なんて書かずとも、配列をぐるぐる回しながら処理することが出来ます。
eachの後ろにdo-endブロックを書く方法と、{}でブロックを作ってその中で、処理を書く方法があります。下の例は全く同じ処理です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | array1 = [1, 2, 3] array1.each do |i| puts i + 10 end #=> 11 #=> 12 #=> 13 array1.each{ |i| puts i + 10 } #=> 11 #=> 12 #=> 13 |
合致する要素だけ抜き出して処理するfind
array.find(ifnone = nil){|item| block }
item 各要素
block itemを使った条件式(booleanを返す)
eachのようにぐるぐる回しながら、指定した条件に合致している要素が見つかれば、その要素を返します。ただし、条件に合致した要素を返したら、そこでループ処理は終了するので、見つけられる要素は初めの1つだけ。
もし条件に合致するものが1つもなければnilを返す。
1 2 | array1 = ["foo", "var", "baz"] p array1.find(){|item| item=="foo" } #=> "foo" |
↑こんなことするなら上記のinclude?関数を使ったほうが早いし分かりやすい。
数値に対して使えば便利に使えると思う。
1 2 3 4 | array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] p array1.find(){|i| i%3==0 } #=> 3 p array1.find(){|i| i>15 } #=> nil |
全部が条件に合致すればtrueを返すall?
array.all?{|item| block }
item 各要素
block itemを使った条件式(booleanを返す)
全部の要素が上限に合致すればtrueを返し、もし1つでも条件に合致しない要素があればそこでループ処理を終了してfalseを返す。
1 2 3 4 | array1 = [12, 32, 3, 71, 50, 15, 1, 80, 93, 28] p array1.all?{|i| i<100 } #=> true p array1.all?{|i| i>10 } #=> false |
1つでも条件に合致すればtrueを返すany?
all?関数のany版です。全部ではなくどれか1つでも合致すればtrueを返します。
1 2 3 4 5 6 | array1 = [12, 32, 3, 71, 50, 15, 1, 80, 93, 28] p array1.any?{|i| i<100 } #=> true p array1.any?{|i| i>10 } #=> true p array1.any?{|i| i>100 } #=> false |
any?関数、all?関数共に、ブロック引数なしで使うことも出来ます。ただしその場合、数値は0も含めてtrueと判断され、文字列も空文字””も含めtrueと判断されます。
1 2 3 | array2 = [0, 1, 2, "foo", "" nil] p array2.all? #=> false 全てtrueかどうか p array2.any? #=> true 1つでもtrueがあるかどうか |
配列に要素を追加する 「<<」
「<<」を使えば簡単に配列の最後尾に1つ要素を追加することが出来ます。
1 2 | array1 = ["foo", "var"] array1 << "baz" |
「<<」の左側の配列(レシーバ)に右側のオブジェクトを要素として最後尾に加えます。見たままです。
この操作は、レシーバー自身を変更し、戻り値は変更されたレシーバです。なので、複数つなげることも出来ます。
1 2 | array1 = ["foo"] p array1 << "var" << "baz" #=> ["foo", "var", "baz"] |
配列と配列をつなぐ 「+」
上記の「<<」は、1つの要素を配列に追加するというものですが、要素ではなく配列をつないでしまうのが「+」です。
1 2 | array1 = ["foo", "var"] p array1 + ["baz", "baa"] #=> ["foo", "var", "baz", "baa"] |