計算機のプログラムの役割の大きな柱のひとつが データ処理である。多くの数のデータを処理できるプログラムは有用である。 Rubyでは配列を利用することで、多くのデータを処理するプログラムを手軽に作 ることができる。ここでは、配列に対するより本格的な操作メソッドを 覚えていこう。
これまで配列を生成する方法をいくつか紹介したが、ここで それらをまとめておく。
プログラム中に書く「具体的な値」のことをリテラルという。 たとえば、整数でいえば 5 、文字列でいえば "abc" のようなものを リテラルという。
配列の場合、具体的な値、つまり、リテラル表記は大括弧で 囲ってカンマ(,)で区切って書いたものとなる。
[1, 2, 3, "abc"]
は、要素として、数値 1、数値 2、数値 3、文字列"abc"
を含む配列を意味する。
Array.newによる初期化】
指定したサイズ(長さ)の配列を生成する。
Array.new(5)
は、
[nil, nil, nil, nil, nil]
を生成する。また
Array.new(5, "a")
のように、第2引数には初期値を指定でき、これは、
["a", "a", "a", "a", "a"]
を生成する。
配列に備わるメソッドのうち有用なものを選んで説明する。 以下の説明では変数xに、配列
[3, 4, 1, 2]
が代入されているものとする。たとえば、説明文中に
x.sort
と書いてあった場合は、
[3, 4, 1, 2].sort
というメソッド呼出しが行なわれたことをイメージするとよい。 irbで実際に操作しながら読み進めると分かりやすいだろう。
+ other - 配列の連結
メソッド +は、元の配列と別の配列
otherを繋げた新しい配列を返す。
x = [3, 4, 1, 2] y = [9, 8, 7]
としたとき
x + y
=> [3, 4, 1, 2, 9, 8, 7]
x => [3, 4, 1, 2] y => [9, 8, 7]
<< obj - 配列末尾への破壊的要素追加
メソッド << は、配列の末尾に新しい要素を
追加する。元の配列自体が変更される。
x << 5
=> [3, 4, 1, 2, 5]
x
=> [3, 4, 1, 2, 5]
このように、元の(配列の)値を直接書き換える操作を 破壊的操作という。
concat (other) - 配列の破壊的結合
引数に指定した配列 otherを、元の配列の末尾につなげる。
y = [9, 8, 7]
x.concat(y)
=> [3, 4, 1, 2, 9, 8, 7]
x
=> [3, 4, 1, 2, 9, 8, 7]
y
=> [9, 8, 7]
each ブロック - 各要素に対するブロックの評価
配列の各要素に対して後続するブロックを 繰り返し評価する。
x.each do |i| ……各要素を変数 i に代入して繰り返す…… end
これは、for によるループに書き換えることができる。
for i in x ……各要素を変数 i に代入して繰り返す…… end
これら2つのブロックは同じ働きをする。
以下の2つの部分プログラムはいずれも配列xの
すべての要素(数値)の合計を求めるものである。
ss=0 x.each do |j| ss += j end
ss=0 for gege in x ss += gege end
index(val) - 指定要素の発見
配列の中に、引数に指定した値 val に等しいものが
あるか調べ、最初に見つかった位置(添字)を返す。見つからなかった場合は、
nil を返す。
x = [3, 1, 2, 4] x.index(3) => 0 x.index(4) => 3 x.index(5) => nil
length - 配列の長さを返すsize - 配列の長さを返す
配列の長さ(要素数)を返す。
x.size
=> 4
joinjoin(sep) - 配列を結合して文字列化
配列の各要素の間に文字列 sep を挟んで連結した
文字列を返す。sep を省略した場合は変数 $,
の値が利用される。$,のデフォルト値はnil
で、その場合挟む文字列は空文字列("")である。
連結時に、配列の各要素は文字列化される。
x.join("/")
=> "3/1/2/4"
x.join(", ")
=> "3, 1, 2, 4"
$,
=> nil
x.join()
=> "3124"
reverse - 配列の逆順配列
配列の要素を全て逆順に並べた配列を返す。
x = [3, 1, 2, 4]
x.reverse
=> [4, 2, 1, 3]
xの値は変わらない。
x
=> [3, 1, 2, 4]
reverse! - 配列の逆順配列(破壊的)
reverseと同様だが、元の配列を破壊的に
並べ換えて逆順にしたものを返す。
x = [3, 1, 2, 4]
x.reverse!
=> [4, 2, 1, 3]
xの値は変わる。
x
=> [4, 2, 1, 3]
shift - 先頭要素の取り出し
配列の先頭要素を取り出し、その値を返す。配列はひとつずつ前に 詰められる。
x = [3, 1, 2, 4] x.shift => 3 x => [1, 2, 4]
これを繰り返すと、配列の要素を先頭から取り出すループが、
while i=x.shift
printf("%d\n", i)
end
のように作成でき、以下の出力が得られる。
3 1 2 4
ループから抜けたときのxの値は
[]となる。
unshift(val) - 先頭への要素の追加
配列の先頭に val を追加し、その配列を返す。 各要素はひとつずつ後にずれる。
x = [3, 1, 2, 4] x.unshift(20) => [20, 3, 1, 2, 4] x => [20, 3, 1, 2, 4]
uniquniq! - 重複要素の削除
配列から重複した要素を取り除き、取り除いた部分を前に詰めた 配列を返す。
z = [1, 0, 2, 0, 3, 9, 7, 7, 1, 3, 2, 6, 5, 2]
z.uniq
=> [1, 0, 2, 3, 9, 7, 6, 5]
zの値は変わらない。
z
=> [1, 0, 2, 0, 3, 9, 7, 7, 1, 3, 2, 6, 5, 2]
いっぽう、uniq! は、元の配列を破壊的に
書き換えて、重複したものを取り除いた配列を返す。
z = [1, 0, 2, 0, 3, 9, 7, 7, 1, 3, 2, 6, 5, 2] z.uniq! => [1, 0, 2, 3, 9, 7, 6, 5] z => [1, 0, 2, 3, 9, 7, 6, 5]
select ブロック
- 条件を満たす要素の選択
配列の要素をひとつずつ取り出しブロック
に渡し,ブロックが真(false以外)を返す要素のみからなる新規配列を返す。
複数の要素から特定の条件を満たすもののみ選び出したいときに利用する。
たとえば,z が以下の内容のときを考える。
z = [1, 0, 2, 3, 9, 7, 6, 5]
この場合に偶数のみを含む配列を得たいときは, 「2で割った余りが0に等しいもの」を選ぶことで偶数を選別できる。
even = z.select {|i| i%2 == 0} => [0, 2, 6]
ブロック先頭にある |i| は,順次取り出す要素を変数
i に代入しつつ繰り返すことを意味する。i
に代入された値で i%2 を計算し,それを0と比較する
ことを繰り返している。
数値に限らずどのような要素でも適用できる。以下の配列
f から,ひらがなで始まるもののみを選んでみる。
f = ["柿", "りんご", "サクランボ", "桃", "いちご"] hira = f.select {|el| /[ぁ-ん]/ =~ el} => ["りんご", "いちご"]
reject ブロックreject! ブロック
- 条件を満たす要素の削除
select メソッドの逆で,
条件を満たす要素を削除する。reject
には破壊的メソッド reject! がある。
f => ["柿", "りんご", "サクランボ", "桃", "いちご"] f.reject{|i| /[ぁ-ん]/ =~ i} => ["柿", "サクランボ", "桃"] f => ["柿", "りんご", "サクランボ", "桃", "いちご"] f.reject!{|i| /[ぁ-ん]/ =~ i} => ["柿", "サクランボ", "桃"] f => ["柿", "サクランボ", "桃"]
sortsort ブロック- 配列の内容のソート
配列の内容を並べ換える。ブロック を指定しない場合は
各要素を、演算子 <=> で比較して
小さい順(昇順)に並べ換える。並べ換える規準を変えたいときには
引数を二つ取るブロック を指定する。具体的には
配列.sort {|x, y| xとyの比較式}
のように書く。たとえば、大きい順(降順)に並べ換えたい場合は、
z = x.sort{|x, y| y <=> x}
などとする(xとyの順番に注目)。
sort_by ブロック-
配列の内容の効率的ソート
ブロックを渡す sort 同様だが、ソート基準とする
値を取り出す式のみ指定する。つまり、
配列.sort {|x| 比較すべき値を取り出す式}
のようにする。 ハッシュの value の大小関係でソートしたいときに有用で、 たとえば
item = {
"アルカリ異音水" => 150,
"おでんつゆ" => 50,
"マグロの煮こごり" => 500
}
という商品名vs.単価リストを持つハッシュの商品名を 単価の小さい(安い)順に並べ換えるには以下のようにする。
item.keys.sort_by{|x| item[x]}