組み込みクラス: modules編
RExをやっている限り頻出範囲という印象を受けるので、ちゃんと覚えておきたい。
Enumeratable
Enumeratableモジュールはeachメソッドが定義されたクラスで使用可能となる。
map, collect破壊的
与えられたブロックを評価した結果の配列を返す。
ブロックを与えなくても、エラーにはならず、Enumerator
オブジェクトが返る。
irb(main):038:0> array = [1,2,3,4,5,6,7,8,9] => [1, 2, 3, 4, 5, 6, 7, 8, 9] irb(main):039:0> array.map => #<Enumerator: [1, 2, 3, 4, 5, 6, 7, 8, 9]:map> irb(main):040:0> array.map{|a| a * 2} => [2, 4, 6, 8, 10, 12, 14, 16, 18] irb(main):042:0> p array [1, 2, 3, 4, 5, 6, 7, 8, 9] => [1, 2, 3, 4, 5, 6, 7, 8, 9]
each_with_index
ブロックに、配列の中身とインデックスを渡す。
mapやcollectと異なり、あくまでeach~end
の延長線なので、評価済みの配列が返ってくるわけではない。返り値は元の配列にすぎない。
ただし、インデックスは渡さなくてもエラーにはならないようで、配列の中身だけがブロックに渡される。
irb(main):044:0> array.each_with_index{|v| p v} 1 2 3 4 5 6 7 8 9 irb(main):048:0> array.each_with_index{|v,i| p v * (2*i)} 0 4 12 24 40 60 84 112 144 => [1, 2, 3, 4, 5, 6, 7, 8, 9]
inject
なんか不自然な気もしてしまうが、エイリアスにreduce
がある。
畳み込み演算、というものを行うメソッド。
injectの引数を初期値として、初期値と配列の先頭を使った演算を行い、次にその結果と配列の2番目を使った演算を行い....ということを繰り返す。
injectの引数は省略でき、その場合は初期値は配列の先頭、最初の演算は「配列の先頭と2番目」を使って行われる。
irb(main):061:0> [1,2,3,4,5,6,7].inject(1){|init,new_val| init + new_val } => 29 irb(main):067:0> [1,2,3,4,5,6,7].inject(0){|init,new_val| init + new_val } => 28 irb(main):068:0> [100,1,2,3,4,5,6,7].inject{|init,new_val| init + new_val } => 128
each_cons
引数で渡された数ずつ、要素を配列で渡していく。一回に渡す要素は渡す回数が増えることに、indexがインクリメントされていく。 例えば10個の要素に対してこのメソッドに3の引数が渡されたら、要素は「1,2,3」「2,3,4」「3,4,5」...となる。これが繰り返される。
irb(main):071:0> [1,2,3,4,5,6,7].each_cons(2){|items| p items.class} Array Array Array Array Array Array => nil irb(main):074:0> [1,2,3,4,5,6,7].each_cons(2){|items| p items} [1, 2] [2, 3] [3, 4] [4, 5] [5, 6] [6, 7] => nil irb(main):073:0> {:a => "tokyo", :b => "maebashi", :c => "yokohama", :d => "odawara", :e => "ehime"}.each_cons(2){|items| p items } [[:a, "tokyo"], [:b, "maebashi"]] [[:b, "maebashi"], [:c, "yokohama"]] [[:c, "yokohama"], [:d, "odawara"]] [[:d, "odawara"], [:e, "ehime"]] => nil
相手が配列だろうが、ハッシュだろうが、要素は配列で渡されている。
each_slice
要素を指定された数で「区切って」渡す。(each_consとの違いは「区切り=slice」と覚える。)
当然、配列の最後部では指定された要素に足らないことも起こりえる。
irb(main):002:0> [1,2,3,4,5,6,7,8,9].each_slice(4){|items| p items} [1, 2, 3, 4] [5, 6, 7, 8] [9] => nil
reverse_each
eachを逆順に要素を渡す。
all?, any?, one?, none?
trueを返す条件はそれぞれ
all?: 配列のすべて any?: 真が一つでもあれば one?: 真が一つだけあれば none?: 真が一つもなければ
メソッド | 意味 |
---|---|
all? | 配列のすべて |
any? | 真が一つでもあれば |
one? | 真が一つだけあれば |
none? | 真が一つもなければ |
後ろにブロックをとって判定することもできる。
irb(main):007:0> [false,false,"HelloWorld",false,false].one? => true irb(main):011:0> [0,0,0,false,0].none? => false
C言語では0はfalseと同意だが、Rubyでは,nil
とfalse
以外はtrueになるので、注意する。
irb(main):013:0> [false,false,true,false,false].one?{|item| p item} false false true false false => true irb(main):014:0> [false,false,true,false,false].any?{|item| p item} false false true => true
oneは配列のすべての要素を確認して、配列に一つだけしか存在しないことを確かめる必要があるのに対して、anyは配列に一つでも要素があればtrueを返せる。よって処理の長さも各メソッドで異なる。
find
エイリアスはdetect
。ブロック評価で最初に真になる要素を返す。
(selectとのエイリアスの混同が起こりそうだが、deletectは「検知」を意味するので「検知をした時点で処理を終了している」と考えてみる。)
find_all
エイリアスはselect
(「selectボタンは複数選択」と覚えてみる。)
reject
find_all
と対の関係。ブロック評価でfalseになったものすべて。
grep
===
メソッドでイコールの関係になるものすべてが返ってくる。正規表現オブジェクトを引数に持ってくることを想定していると思われる。
irb(main):017:0> [1,3,5,3].grep(3) => [3, 3]
sort_by
sortと似たような動きをするが、ブロックを渡すと、それを評価基準としてソートを行う。sortでは、ブロックを渡す場合2つ以上の要素が渡されないと意味がないが、sort_byの場合、これは一つで良い。
irb(main):019:0> [100,10,10000,99].sort_by{|item| item} => [10, 99, 100, 10000] irb(main):023:0> [100,10,10000,99].sort{|item| item} => [99, 10000, 10, 100]
max_by,min_by
sortとsort_byの違いのような関係。max_byを用いるとブロックに渡すのは「評価基準」だけで良い。一方sortでブロックを渡した場合、ソート処理の方法に関しても記述する必要がある。
irb(main):028:0> ["100","10","10000","99"].max{|item| item.length} => "99" irb(main):030:0> ["100","10","10000","99"].max{|i,i2| i.length <=> i2.length} => "10000" irb(main):031:0> ["100","10","10000","99"].max_by{|i| i.length} => "10000"
group_by
ブロックの評価結果をキーとして、同じキーを持つ要素を配列にしたハッシュを返す。
irb(main):032:0> (1..100).group_by{|v| v % 7} => {1=>[1, 8, 15, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 99], 2=>[2, 9, 16, 23, 30, 37, 44, 51, 58, 65, 72, 79, 86, 93, 100], 3=>[3, 10, 17, 24, 31, 38, 45, 52, 59, 66, 73, 80, 87, 94], 4=>[4, 11, 18, 25, 32, 39, 46, 53, 60, 67, 74, 81, 88, 95], 5=>[5, 12, 19, 26, 33, 40, 47, 54, 61, 68, 75, 82, 89, 96], 6=>[6, 13, 20, 27, 34, 41, 48, 55, 62, 69, 76, 83, 90, 97], 0=>[7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98]}
first
引数を指定して先頭から要素を指定された分だけとっていく。 takeがエイリアスであるが、firstの場合のみ引数を指定しないで、最初の要素だけ取得することが可能。
drop
takeと対になる。(つまり必ず引数を指定する。) 先頭から指定した数だけ要素を切り落とす。(shiftの連続版だが、shiftは破壊的。)
take_while
ブロックを渡す。最初から順番にブロックで評価していき、ブロックの評価が偽になるまでを返す。
irb(main):035:0> station = %w|tokyo shinagawa shinyokohama odawara atami mishima shinfuji shizuoka| irb(main):047:0> station.take_while{|e| e != "atami" } => ["tokyo", "shinagawa", "shinyokohama", "odawara"]
熱海まではブロックの評価がtrueであったが、熱海でfalseとなったため、東京から小田原までが表示されている。
drop_while
take_while
と対になる。最初から順番にブロックで評価していき、ブロックの評価が真になるまでを返す。
dropだとわかりにくいが、最初に真になった 要素なので、以下のように使える。
irb(main):048:0> station.drop_while{|e| e != "atami" } => ["atami", "mishima", "shinfuji", "shizuoka"]
熱海までは評価が真だったが、熱海で初めて評価が真となったため、そこまでが切り落とされている。