このレッスンでは、これまでにも何度か取り上げてきましたArray(配列クラス)について詳しく学んでいきましょう。今回学ぶのは以下のような部分です。メソッドやパーセント記法(%wと%i)というものを使った配列の作り方についてです。
インデックスとは見出しのような意味です。配列の要素にはそれぞれインデックスとして番号が振られています。その使用方法についてのセクションです。
・配列を「集合」と捉える、配列を「列」と捉える配列で使われるメソッドには配列を「集合」として扱うものと「列」として扱うものがあります。その使い方などについてのセクションです。
・配列のメソッド
配列のメソッドは配列に要素を追加したり削除したり、要素を並べ替えたりするものなど様々あります。その使い方などについてのセクションです。
・イテレータ
配列内の要素1つ1つでそれぞれ処理を実行したい場合などには、一般的にイテレータ(繰り返し)がよく使われます。その使い方などについてにセクションです。
・配列内要素の処理
イテレータ以外でも配列内の要素に処理を行う方法が存在しています。その方法などについてのセクションです。
・複数の配列へのアクセス
配列はどんな種類のオブジェクトでも要素とすることが出来ます。その際の注意点などについてのセクションです。
これまでにも何度か配列について取り上げてきました。ここで1度配列について復習しておきましょう。配列とはオブジェクトの集まりです。
上記画像でいうと青背景の部分が配列ですね。配列にはこの例だと3つの要素が含まれておりその要素1つ1つに見出しとして番号が振られています。この番号を「インデックス」もしくは「添字」と呼びます。
この番号は0から順に振られていくので要素が3つでも「0、1,2」となります。この配列に「sports」と書かれた名札が付いていますね。これは変数を表しているのでコードにすると以下のようになります。
sports = ["野球", "サッカー", "テニス"]
配列では以下のようなことが行えます。
・インデックスを指定して要素を取り出す
p sports[1]
#=> "サッカー
・インデックスを指定し、オブジェクトを格納する
sports[1] = "水泳"
p sports
#=> ["野球", "水泳", "テニス"]
・イテレータ(繰り返し)を使い、要素を1つずつ取り出す
sports.each do |sport|
p sport
end
#"野球"
#"水泳"
#"テニス"
これまでこのような事を学んできましたね。では、配列について更に学んでいきましょう。
配列の作るときは、これまで以下のように書いてきました。
sports = ["野球", "サッカー", "テニス"]
この書き方以外でも配列を作ることが出来るのです。では見ていきましょう。
クラスのインスタンスを作る時には、「〇〇(クラス名).new」と書くんでしたね。もちろん配列クラスでも同じですので以下のようなコードになります。
a = Array.new
#=> []
b = Array.new(3)
#=> [nil, nil, nil]
c = Array.new(3, 1)
#=> [1, 1, 1]
「a」は引数を指定していません。そうすると空の配列が作成されます。「b」は引数を1つ指定しています。Array.newの場合の引数の1つ目は配列内の要素数の指定という事になります。ですので3つの要素が格納されていますね。
ただし、要素の内容は指定していないので「nil」が要素となっています。「c」は引数を2つ指定しています。この場合2つ目の引数は要素の内容になります。例では1という数値を指定しているので、1が3つ格納されています。
また、Array.newをブロック付きメソッドとして実行すると以下のようなこともできます。これは、3つの要素を作ると指定したうえでブロック内に書いた文字列を配列の要素1つ1つに代入しています。ブロック変数(「i」)も使用していますね。
Array.new(3) do |i|
"インデックス#{i}の要素です"
end
#=> ["インデックス0の要素です", "インデックス1の要素です", "インデックス2の要素
まずは「%w」からみていきましょう。これは文字列が要素となる配列を作る場合に使われます。書き方は以下のようになります。
配列名(変数) = %w(要素 要素 要素)
このように「%w」の後ろに要素を「 ( ) 」で囲って指定します。要素と要素の区切りは半角スペースで書きます。
test = %w(おはよう こんにちは こんばんは)
#=> ["おはよう", "こんにちは", "こんばんは"]
この配列の作り方であれば「 " " 」や「 , 」を書かなくても良いので、手間が省けるということとコードがすっきりとして読みやすくなるというメリットがあります。
続いて「%i」です。こちらはシンボルが要素となる配列を作る際に使います。
test2 = %i(Name Age Address)
#=> [:Name, :Age, :Address]
これら2つの例では要素を囲うのに「 ( ) 」を使用していますね。この要素を囲う記号は他の記号でも良く以下の記号などが使えます。しかしコードが分かりにくくなってしまってはいけないので、一般的によく使われている「 ( ) 」「 < > 」「 | | 」の中のいずれかを使用すると良いでしょう。
( ) < > | | ! ! @@ %%
この記号は、例えば以下のように要素全てを囲う記号と同じ記号を文字列に含める必要がある際などに、要素全体を囲うの方を他の記号に変えてコードを見やすくすることが出来ますね。
test3 = %w(A(B)C D(E)F)
#=> ["A(B)C", "D(E)F"]
配列の作成方法はこれまでに3通り出てきました。この3つの作り方が使われることが多いのですが、他にも配列を作る方法はあるのでご紹介しようと思います。
まず「to_a」メソッドです。これは他のクラスに属するオブジェクトを配列オブジェクトに変換できます。ではハッシュオブジェクトを配列オブジェクトに変換するという例を見てみましょう。
h = {"キー" => "値", "キー2" => "値2"}
p h.to_a
#=> [["キー", "値"], ["キー2", "値2"]]
ハッシュオブジェクトを変換する場合だけ他のオブジェクトとは異なる点があります。それは上記の様に、キーと値を分け2つの要素として持つ配列が作られ、その配列を要素として持つ配列を作っていますね。
to_aと同じようにこの「spilt」も他のクラスのインスタンスを配列オブジェクトに変換します。このメソッドは以下のように使います。
配列名(変数) = "要素,要素,要素".split(',')
「 " " 」で要素全体を囲い、要素と要素の区切りはsplitメソッドの引数で指定した区切り文字を使い記述します。この場合は区切り文字として「 , 」を指定しています。では例を見てみましょう。
bunkatsu = "2018/4/1,Spring SALE,30%OFF".split(',')
#=> ["2018/4/1", "Spring SALE", "30%OFF"]
この場合も区切り文字として「 , 」を指定していますね。すると区切り文字以外は文字列の一部として認識されるので「Spring」と「SALE」の間の半角スペースもきちんとそのまま出力されています。
ここまで配列の作り方などについて学びました。ここからは配列オブジェクトの操作方法などについて学んでいきたいと思います。では、インデックス(見出し番号)の使い方について見ていきましょう。
配列の復習のセクションにてインデックスを指定して要素を取り出す方法を取り上げました。
p sports[1]
#=> "サッカー
この場合は取り出している要素は1つです。では、複数の要素をインデックスを指定し取り出す方法を見てみましょう。
以下のようにインデックス指定の部分でマイナスの値を指定する事が出来ます。
array = ["あ", "い", "う", "え", "お"]
p array[-2]
#=> "え"
-2と指定すると要素「"え"」が返ってきています。これはマイナスの値を指定すると配列内の要素を後ろから数え返すとなっている為です。この例の場合後ろから2番目の要素は「"え"」になります。
範囲を指定すると範囲内の複数の要素を配列として取り出すことができます。では、例をみてみましょう。
p array[1..3]
#=>["い", "う", "え"]
この例の場合「..」としていますが「...」も使えます。これまでの章でも取り上げましたが「...」の場合は指定した範囲の最後の要素は範囲に含まれないので、上記例だと「"い", "う"」という要素のみが配列になります。
インデックスの部分で配列内の要素数を超える範囲を指定した場合は、超えてしまった分の指定を無視します。しかし、エラーなどが起こることはなく範囲内に存在する要素を配列で返してくれます。
p array[1...10]
#=>["い", "う", "え", "お"]
この場合は以下のように指定します。
配列名[スタートのインデックス番号,取り出す個数]
スタートのインデックス番号を指定し、その番号から数え始め何個分取り出すかという指定の仕方です。では、例をみてみましょう。
p array[1,2]
#=>["い", "う"]
この例だとスタートのインデックス番号を1としているので「"い"」ですね。そして、2個の要素を取り出すよう指定しているのでこの結果となります。
これまでの例で使用してきた「 [ ] 」ですが、全く同じ働きをするメソッドがあります。
これらを使用することも可能なんですね。しかし、一般的に「 [ ] 」の方がよく使われるので特別な理由がなければ「 [ ] 」で良いかと思います。
ここまでのセクションでは要素を取り出すということをしてきました。このセクションでは、配列内の要素を置き換えるということをしてみましょう。この場合も「 [ ] 」を使用します。(atかsliceでも出来ます)
置き換える
要素を置き換えるには以下のように書きます。
配列名[インデックス番号] = 新しい内容
では、実際にやってみましょう。
array[0] = "ア"
p array
#=> ["ア", "い", "う", "え", "お"]
複数の要素の置き換え
先程は1つの要素を置き換える場合の方法でした。ここでは、複数の要素を指定し置き換えてみましょう。インデックス番号の範囲の指定は取り出す際と同じです。では、例をみてみましょう。
array[2..4] = ["ウ", "エ", "オ"]
p array
#=> ["ア", "い", "ウ", "エ", "オ"]
このように要素の新しい内容を配列にして書きます。
挿入する
配列に新要素を挿入することも出来ます。これは、先程の置き換えを応用した形で行います。
array[1, 0] = ["ひらがな", "カタカナ"]
p array
#=> ["ア", "ひらがな", "カタカナ", "い", "ウ", "エ", "オ"]
まずインデックス番号1の後ろに新要素を挿入すると指定しています。そして取り出す場合はいくつ要素を取り出すかとしていた部分には「0」が指定されていますね。これは、今回は「挿入する」のでどの既存要素とも置き換えるということはしません。この部分が置き換える要素数を入れる部分である為ということですね。
要素を取り出すというセクションで、複数の要素を1度に取り出す方法を学びました。しかしこの方法だとインデックス番号の1と3というように飛ばして取り出すことが出来ません。このように順番を飛んで取り出したいときは「values_at」というメソッドを使います。では使い方をみてみましょう。
p array
#=> ["ア", "ひらがな", "カタカナ", "い", "ウ", "エ", "オ"]
p array.values_at(1,3)
#=> ["ひらがな", "い"]
「配列名.values_at」とし引数でインデックス番号を指定します。
ここまでのセクションではインデックス番号を指定し要素を取り出したり、挿入をしたりという事を学んできました。これは、配列内の要素にきちんとした順番が決まっている事が前提となっています。
この配列とは異なり、要素の順番が定められていない集合と呼ばれるオブジェクトがあります(Setクラスに属す)。このオブジェクトは「1,2,3」も「2,1,3」も同じものと考えることが出来ます。このセクションでは配列を「集合」と捉えた場合の使い方を学びます。
*集合というオブジェクトに変換されたり、Setクラスに属する訳ではなく配列のままで「集合」と「捉える」だけです。
集合の演算は「共通集合」と「和集合」などです。
共通集合
2つの集合の両方ともに含まれている要素を取り出して、新たに集合を作成すること
和集合
どちらか片方に含まれている要素を取り出して、新たに集合を作成するとこ
この2つの集合は「&」と「|」を使い以下のように表されます。
a & b #共通集合
a | b #和集合
では例をみてみましょう。
a = ["あ", "い", "う"]
b = ["う","え","お"]
p (a & b)
#=> ["う"]
p (a | b)
#=> ["あ", "い", "う", "え", "お"]
「a」と「b」という配列には同じ要素のか「"う"」が存在しています。共通集合の方は両方に含まれる要素で新たな配列を作るので「"う"」という要素を持つ配列が出来ています。
和集合の方はそれぞれ一方のみに存在する要素と、両方に存在する要素を全て取り出し配列を作っています。ただし両方に含まれる要素は新たな配列に2つ存在することはなく1つとなっています。
集合の差
集合の演算には「-」を使った差の演算もあります。これは1つ目の集合の要素-2つ目の集合の要素という計算をします。これは1つ目の集合要素から2つ目の集合で1つ目の集合要素と同じものを除くという事です。
c = ["あ", "い", "う"]
d = ["い", "う", "え", "お"]
p (c -d)
#=> ["あ"]
「c」と「d」で同じ要素は「"い"」と「"う"」ですね。この2つは除かれます。「d」の「"え"」と「"お"」は「c」には存在していないので新たな配列には入りません。
「|」と「+」は配列同士を結合する事の出来るメソッドです。この2つの違いは同じ要素が含まれている場合、新たな配列に同じ要素がいくつ入るかという所です。「|」は同じ要素は1つとなり、「+」は同じ要素が2つ新たな配列に入ります。では確認してみましょう。
p (c | d)
#=> ["あ", "い", "う", "え", "お"]
p (c + d)
#=> ["あ", "い", "う", "い", "う", "え", "お"]
先ほどは配列を集合と捉えた場合の使い方を学びました。このセクションでは配列を「列」として捉えた場合の使い方を学んでいきます。
この「列」という捉え方をすると、「要素を追加する・追加要素を取り出す」という事が行える、キューやスタックと呼ばれるものとして配列を使う事が出来ます。では以下図をみてみましょう。
「キュー」は要素を追加した順番で取り出すことのできるものです。このデータ構造は「FIFO(First-in First-out)」と呼ばれることもあります。
「スタック」は要素を追加したときの順番の逆の順番、つまり最後に追加された要素から取り出すこともできます。このデータ構造は「LIFO(Last-in First-out)」と呼ばれることもあります。
では実際の使い方を見ていきましょう。この「キュー」と「スタック」にはそれぞれ使う事の出来るメソッドがあります。以下表をご覧ください。
先頭要素 | 末尾要素 | |
要素を追加する | unshift | push |
要素を取り出す(削除) | shift | pop |
要素を参照する | first | last |
ではこれらのメソッドを使ってみましょう。
array = ["1", "2", "3"]
p array.push("4")
#=>["1", "2", "3", "4"]
p array.shift
#=> "1"
まず1行目で要素が3つある配列が作られています。そして2行目で末尾に4つめの要素が追加されています。この例だと先頭の(最初に追加された)要素は「"1"」です。
そして、3行目で「Shift」で1つ目の要素を取り出して(削除して)います。このようにキューの場合は、要素を追加するときは「push」取り出すときは「shift」を使います。
p array.push("4")
#=>["1", "2", "3", "4"]
p array.pop
#=> "4"
これは「スタック」の場合ですね。スタックは最後に追加した要素から取り出すので「pop」を使います。
配列に新たに要素を追加する場合のメソッドを挙げていきます。
unshift
配列の先頭に新たな要素を追加します。
配列名.unshift(追加したい要素)
array = [1, 2, 3]
array.shift(0)
pushと<<
この2つは同じ働きをします。配列のに新たな要素を追加します。
配列名.push(追加したい要素)
配列名 << 追加したい要素
array << 4
concat / +
この2つのメソッドは同じ働きをします。配列に別の配列を連結させ、1つの配列にします。ただし、異なる点があります。それは、「concat」は
破壊的なメソッド / freeze
オブジェクト(配列など)の値を変更してしまうメソッドを破壊的メソッドといいます。では破壊的メソッドの1つである「pop」を使った例を見てみましょう。
array = [1, 2, 3]
copy = array
p copy
#=> [1, 2, 3]
array.pop
#=> 3
p array
#=> [1, 2]
p copy
#=> [1, 2]
上記例では配列「array」に対し「pop」メソッドを使っています。配列内の最後の要素である「3」が取り出されて(削除されて)います。その後「p array」とすると「3」が削除された配列が返ってきています。
これは「pop」でオブジェクト(配列)の値を変更したという事になりますね。上記例の中で「copy」という「array」をコピーしたオブジェクトも作成しています。この場合コピー元の「array」が「pop」という破壊的メソッドで値を変更しているので「copy」の値も変わってしまっています。
破壊的メソッドの中には同じ名前の非破壊的メソッドを持つものもあります。ではその中から「downcase」という大文字を小文字に変換して返すメソッドを使った例を挙げてみます。
str = "GOODBYE"
str.downcase
#=> "goodbye"
p str
#=> "GOODBYE"
str.downcase!
#=> "goodbye"
p str
#=> "goodbye"
同じ「downcase」という名前のメソッドですが「!」がついているのが破壊的メソッド、ついていないのが非破壊的メソッドです。このように同じ名前で非破壊的メソッドも持つものは区別する為「!」が付いています。
まず「str」という変数に大文字の単語を代入しています。そして最初に「str」に対して非破壊的メソッドの方の「downcase」を使っています。すると小文字に変換して返してくれますが、変数の値を確認すると値は変わっていないことが分かります。次に破壊的メソッドの方です。こちらを使った後に変数の値を確認すると値が変更されていることが分かりますね。
この破壊的メソッドを使って値を変更されてしまわぬよう、オブジェクトの値に変更禁止の制限の様なものをかけることもできます。その場合「freeze」というメソッドを使います。
array.freeze
array.pop
#RuntimeError: can't modify frozen Array
「array」には「freeze」で変更禁止としているので破壊的メソッドがエラーで使えなくなっていますね。このように「freeze」を使うと値を変更出来なくなるのですが「dup」というオブジェクトをコピーするためのメソッドを使えば複製した方のオブジェクトの値は変更できるようになります。
b = array.dup
b.pop
#=> 3
p array
#=> [1, 2, 3]
p b
#=> [1, 2]
c = array
c.pop
#RuntimeError: can't modify frozen Array
d = c.clone
d.pop
#RuntimeError: can't modify frozen Array'
「dup」の他にもオブジェクトコピーの方法には「コピー先 = コピー元」としたり、「clone」というメソッドを使う方法もあります。しかしこの2つはコピー元のオブジェクトは「freeze」を使ったという事までコピーするので複製したものも値の変更は出来ません。
配列から要素を取り除くためのメソッドをご紹介します。
配列内の要素に「nil」のものがあれば取り除きます。では例を見てみましょう。
a = ["あ", nil, nil, 1]
a.compact
#=> ["あ", 1]
きちんと「nil」のもの以外を返していますね。この例のように配列内に「nil」のものが存在していない場合は、「compact」であれば何も取り除かず元の配列が返り、「compact!」の場合は「nil」が返ってきます。
これは引数の部分で取り除きたい要素を指定する事が出来ます。破壊的メソッドです。
a = ["あ", "い", 1, 2]
a.delete("あ")
p a
#=> ["い", 1, 2]
こちらは引数の部分で取り除きたい要素を「インデックス番号」で指定します。こちらも破壊的メソッドです。
a.delete_at(0)
p a
#=> [1, 2]
配列「a」のインデックス番号0の要素を取り除きました。
この2つは同じ働きをします。またブロック付きメソッドとして使用します。では例を見てみましょう。
a = ["りんご", "さくらんぼ", "なし", "パイナップル"]
a.delete_if{|fruit| 3 < fruit.length }
#=> ["りんご", "なし"]
p a
#=> ["りんご", "なし"]
例では「delete_if」を使用しています。どのようなメソッドかというとブロックの中で書いた処理を要素ごとに実行し、処理の結果が「真」であればその要素は取り除かれます。
例ではブロック内で要素の文字列の長さが3より大きいかどうかを判断しています。ですので4文字以上の「"さくらんぼ"」と「"パイナップル"」は取り除かれていますね。また、「delet_if」と「reject!」については破壊的メソッドです。
「slice」は破壊的メソッドです。このメソッドは引数の部分で指定した値を取り除きます。複数の値を指定する事も可能です。
配列名.slice!(インデックス番号)
配列名.slice(インデックス番号..インデックス番号)
配列名.slice(インデックス番号, 取り除きたい個数)
a = [1, 2, 3, 4, 5]
a.slice!(1...3)
#=> [2, 3]
p a
#=> [1, 4, 5]
a.slice!(1, 2)
#=> [4, 5]
p a
#=> [1]
複数の要素を取り除くことが出来ていますね。
配列の中で重複している要素を取り除きます。2つ同じ要素があれば、返される配列内にはその要素は1つとなります。「uniq!」は破壊的メソッドです。
a = [1, 1, 2, 2, 3]
a.uniq!
p a
#=> [1, 2, 3]
重複した要素が取り除かれていますね。
配列内の先頭の要素を取り除きます。こちらも破壊的メソッドです。
a.shift
p a
#=> [2, 3]
こちらは末尾の要素を取り除きます。破壊的メソッドになります。
a.pop
p a
#=> [2]
先ほどは配列内の要素を取り除くという事でしたが、このセクションでは要素を別の要素に置き換えるという事を行います。こちらで紹介するメソッドでも非破壊的メソッドと破壊的メソッドの両方が存在するものがあります。
この2つはブロック付きメソッドとして使います。ブロック内に書いた処理を各要素で実行し、その結果の値で置き換えられます。では例を見てみましょう。
a = [1, 2, 3]
a.collect!{|new| new + 10}
p a
#=> [11, 12, 13]
a.map!{|new| new - 10}
p a
#=> [1, 2, 3]
「collect!」の方では元の配列の要素に10を足して、その結果の値で置き換えられています。そして「map!」の方では「collect!」で置き換えられた要素から10を引いた値で置き換えています。
こちらも破壊的メソッドです。このメソッドは引数で置き換える要素と新しい要素を指定します。指定方法はいくつかあります。
配列名.fill(要素(新)) #A
配列名.fill(要素(新), インデックス番号) #B
配列名.fill(要素(新), インデックス番号, 置き換える個数) #C
配列名.fill(要素(新), インデックス番号..インデックス番号) #D
[1, 2, 3].fill(5) #A
#=> [5, 5, 5]
[1, 2, 3].fill(5, 1) #B
#=> [1, 5, 5]
[1, 2, 3].fill(5, 0, 2) #C
#=> [5, 5, 3]
[1, 2, 3].fill(5, 0..1) #D
#=> [5, 5, 3]
まずAの場合「5」と置き換えるよう指定していますね。このように引数が1つであれば全ての要素が指定した要素に置き換えられます。Bの場合は「5」に置き換えることと、インデックス番号を「1」と指定しています。これはインデックス番号1の要素以降全てを置き換えるというものです。
続いてCの場合はインデックス番号「0」の要素から数え始め2個分置き換えると指定しています。最後にDはインデックス番号「0」から「1」までの要素を置き換えるとしています。
配列の中に配列が含まれているというような場合に、1つの配列に直して返すメソッドです。これを平坦化といいます。
a = [1, 2, [3, 4]]
a.flatten!
p a
#=> [1, 2, 3, 4]
配列内の要素の並び順を逆に並べ替えて返します。
a.reverse!
p a
#=> [4, 3, 2, 1]
こちらはブロック付きでもブロックなしでも使う事が出来ます。ブロックの章でも取り上げましたね。要素の順番を並べ替えるメソッドであり、どのように並べ替えるかを指定したい場合はブロック付きメソッドとして使いましょう。
a = [10, 5, 8, 2]
a.sort!
p a
#=> [2, 5, 8, 10]
こちらもブロックのレッスンで取り上げましたね。「sort」と同じように並べ替えが行われます。
a = ["りんご", "パイナップル", "なし", "さくらんぼ"]
a.sort_by{|fruit| fruit.size}
p a
#=> ["なし", "りんご", "さくらんぼ", "パイナップル"]
配列内の要素1つ1つに対し処理を実行する際などにイテレータ(繰り返し)がよく使用されます。では例を見てみましょう。
num = [1, 2, 3]
num.each do |n|
p n * 2
end
#2
#4
#6
この例では「num」という配列の要素1つ1つに対しそれぞれ処理を実行するために「each」を使っていますね。
また、レシーバが配列ではない場合に「collect」メソッドを使用して配列に変えるという事も出来ます。では例を見てみましょう。
a = 10..15
p a.collect{|i| i - 10}
#=> [0, 1, 2, 3, 4, 5]
「a」には配列ではなく範囲オブジェクトが代入されています。ですが「collect」メソッドを使うと配列となって返ってきます。ブロック内で記述した処理もきちんと実行されていますね。
配列内の要素に対する処理の実行の仕方を挙げていきます。
繰り返しの中でインデックス番号を指定しすれば配列内要素それぞれで処理を実行する事が出来ます。
sports = ["野球", "サッカー", "水泳"]
for i in 0..2
print "人気のスポーツ#{i+1}位は",sports[i],"です\n"
end
#人気のスポーツ1位は野球です
#人気のスポーツ2位はサッカーです
#人気のスポーツ3位は水泳です
繰り返し内で配列名とインデックス番号で配列にアクセスしていますね。
先ほども取り上げましたが「each」を使えば配列内の要素1つ1つに対し処理を実行できますね。しかし「each」ではインデックス番号を得ることは出来ません。インデックス番号が必要な場合は「each_with_index」というメソッドを使います。では先程のfor文の例を「each_with_index」で書いてみましょう。
sports.each_with_index do |sport, i|
print "人気のスポーツ",i+1,"位は",sport,"です\n"
end
#人気のスポーツ1位は野球です
#人気のスポーツ2位はサッカーです
#人気のスポーツ3位は水泳です
インデックス番号を得られていますね。
配列内の要素を取り除き処理を実行するという事を各要素で行います。取り除きながらなので最終的に配列の中身は空になります。
a = [1, 2, 3]
while test = a.shift
p test + 1
end
#2
#3
#4
#=> nil
p a
#=> []
この繰り返しは配列内に要素がなくなるまで繰り返されます。
配列には色々な種類のオブジェクトを格納できます。では様々な例を見ていきましょう。
rubyにはMatrix(行列)というクラスが存在します。その行列オブジェクトを配列で表現する事が出来ます。これは配列の中に配列を書くという方法で行われます。
a = [1, [2, 3]]
a[0][0]
#=> 1
a[1][0]
#=> 2
a[1][1]
#=> 3
このように配列の中の配列にもインデックス番号が振り分けられています。取り出す際、1つめのインデックス番号指定部分ではどの配列かを指定します。全体を囲う配列を0とするので、この場合配列の中配列を指定したい場合は1ですね。そして2つめのインデックス番号指定部分では配列内の要素を指定します。
配列の中に配列を作るということを行いたい場合、初期化には注意すべき点があります。(このセクションでの初期化とは簡単に言うと変数に初期値を設定することです。つまり「Array.new」を使うことです。)では、以下例を見てみましょう。
a = Array.new(3, [1, 2, 3])
#=> [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
このように「Array.new」の引数の部分で作成したい配列の数と作成したい配列の要素を指定すると1つの配列の中に作成する事が出来ます。このそれぞれの配列内の要素「1, 2, 3」は同じオブジェクトとなっています。では確認してみましょう。
a[2][2] = 0
p a
#=> [[1, 2, 0], [1, 2, 0], [1, 2, 0]]
1行目で配列の中の3つ目の配列(インデックス番号は2)の最後の要素(インデックス番号2)を「0」に書き換えていますね。そして配列を参照してみると配列の中の配列の全ての3が0に変わってしまっています。そうではなく「a[2][2] = 0」として1つのみ変えたい場合はブロックを使って指定します。
a = Array.new(3) do
[1, 2, 3]
end
a[2][2] = 0
p a
#=> [[1, 2, 3], [1, 2, 3], [1, 2, 0]]
このようにすると先ほどとは違い見た目は同じ要素ですが、引数で指定した分だけブロックを実行してくれるので、別の要素となっています。ですので最後の配列の要素だけ書き換えることが出来ます。
複数の配列がある時、そのそれぞれの配列の同じインデックス番号の要素にアクセスをする方法です。では例として「zip」メソッドを使ってみましょう。
a1 = [1, 2, 3]
a2 = [1, 2, 3]
a3 = [1, 2, 3]
p a1.zip(a2, a3)
#=> [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
「zip」メソッドは複数の配列の同じインデックス番号の要素を組み合わせ新たな配列を作り返すメソッドです。
test = []
a1.zip(a2, a3) do |a1, a2, a3|
test << a1 + a2 + a3
end
p test
#=> [3, 6, 9]
ブロックを使う事も出来ます。
test = []
a1.zip(a2, a3) do |a1, a2, a3|
test << a1 + a2 * a3
end
p test
#=> [2, 6, 12]
結果を参照するために空の配列を1行目で作成しています。そしてブロック内で配列同士の計算をしていますね。こちらもインデックス番号が同じもの同士で処理が実行されています。
・配列とはオブジェクトの集まり
・配列内の要素にはインデックス(見出し)として番号が振られている
・配列で使えるメソッドには値を変更してしまう破壊的メソッドと非破壊的メソッドがある
・配列を集合や列として見ることが出来る
無料ビデオ講座のお知らせ
Skillhub [スキルハブ]では無料の動画講座を多数公開しています。他校だと数万円するような講座が無料で受講できます。