1年くらい前にRubyの勉強のためにEnumerableモジュールの便利メソッドをまとめたもの
参考
・パーフェクトRuby
・https://docs.ruby-lang.org/ja/latest/class/Enumerable.html
繰り返し
each_with_index
繰り返しの度にインクリメントされる値と一緒に繰り返す
%w(Alpha Bravo Charlie).each_with_index do |code, index|
puts "#{index}: #{code}"
end # => "0: Alpha" "1: Bravo" "2: Charlie"
reverse_each
末尾から逆順に繰り返す
(1..3).reverse_each { |val| puts val } # => 3 2 1
each_slice
要素をn個ずつ区切って繰り返す
(1..5).each_slice 2 { |a, b| p [a, b] }
# => [1, 2] [3, 4] [5, nil]
each_cons
n個の連続した要素を1つずつずらしながら繰り返す
(1..4).each_cons 3 { |a, b, c| p [a, b, c] }
# => [1, 2, 3] [2, 3, 4] nil
cycle
レシーバの要素を先頭から末尾まで繰り返しを永遠に行う
(1..3).cycle { |n| p n } # => 1 2 3 1 2 …
プロックを評価した結果の配列
map
ブロックの戻り値を集めた配列を返す
['ruby', 'rails'].map { |str| str.upcase } # => ["RUBY", "RAILS"]
ブロックの返り値を連結した配列
flat_map
各要素をブロックに渡し、その返り値を連結した配列を返す
[[1,2], [3,4]].flat_map{|i| i.map{|j| j * 2 }} # => [2,4,6,8]
複数の要素を組み合わせる
zip
複数の要素を組み合わせて配列の配列を作る
nums = (1..4)
langs = %w(ruby python java)
arr = [true, false]
nums.zip(arr, langs)
# => [[1, true, "ruby"], [2, false, "python"], [3, nil, "java"], [4, nil, nil]]
arr.zip(nums, langs)
# => [[true, 1, "ruby"], [false, 2, "python"]]
要素が特定の条件を満たしているか
all?
すべての要素が真ならtrue
none?
すべての要素が偽ならtrue
any?
1つでも要素が真ならtrue
one?
1つだけ要素が真ならtrue
[true, true, true].all? # => true
[true, true, false].all? # => false
[false, false, false].none? # => true
[true, true, false].none? # => false
[false, false, true].any? # => true
[false, false, false].any? # => false
[false, false, true].one? # => true
[true, true, false].one? # => false
部分的な要素の取得
grep
正規表現にマッチする各要素を検索する
%w(Alpha Bravo Charlie).grep(/l/i)
# => ["Alpha", "Charlie"]
detect(find)
最初に真となった要素を返す
select
真となった要素をすべて返す
array = [4, 6, 2, 1]
array.detect {|v| v.even? } # => 4
array.select {|v| v.even? } # => 4 6 2
take
先頭から任意の数の要素を配列として返す
drop
先頭から任意の数の要素をスキップして残りの要素を配列として返す
array = %w(a b c d e)
array.take(2) # => ["a", "b"]
array.drop(2) # => ["c", "d", "e"]
take_while
ブロックが最初に偽を返すまでの要素の配列を返す
drop_while
ブロックが最初に偽を返してからの要素の配列を返す
array = %w(a b c d e)
array.take_while { |n| n != 'c' } # => ["a", "b"]
array.drop_while { |n| n != 'c' } # => ["c", "d", "e"]
畳み込み演算
inject(reduce)
ブロックを受け取りブロックは各要素に対して実行する
[1, 2, 5].inject do |result, num|
result + num
end # => 8
[1, 2, 5].inject(:+) # => 8
繰り返しとオブジェクトの更新
each_with_object
引数のオブジェクトを繰り返しの度にブロック引数として渡し最終的には戻り値とする。
numbers = [4, 3, 9]
numbers.each_with_object([]) do |number, result|
result << number + 3
end
要素のグルーピング
group_by
ブロックを評価した結果の戻り値をキーにして新しいハッシュを返す
同一条件ごとに総まとめする。
array = [1, 'a', 2, 'b', 3, 'c']
array.group_by {|val| val.class }
# => {Integer=>[1, 2, 3], String=>["a", "b", "c"]}
partition
ブロックの戻り値が真か偽かによって分けた2つのグループを配列にして返す
array = [1, 'a', 2, 'b', 3, 'c']
array.partition {|val| val.is_a?(String) }
# => [["a", "b", "c"], [1, 2, 3]]
chunk
ブロックの戻り値ごとに要素の並びをまとめた配列を作る。
同一条件ごちに部分まとめする。
array = [1, 'a', 2, 'b', 3, 'c']
enum = array.chunk {|val| val.class }
enum.each {|key, arr| puts "#{key}: #{arr}" }
# 出力結果
Integer: [1]
String: ["a"]
Integer: [2]
String: ["b"]
Integer: [3]
String: ["c"]
slice_before
マッチ要素またはブロックが真を返した要素から次にマッチ or 真の要素までをチャンクしたものを返す。
[0, 2, 4, 1, 8, 3, 5, 7, 10].slice_before(&:even?).to_a
# => [[0], [2], [4, 1], [8, 3, 5, 7], [10]]
最小値と最大値
min
最小値を返す
max
最大値を返す
minmax
最小値と最大値を配列にして返す
range = (1..4)
range.min # => 1
range.max # => 4
range.minmax # => [1, 4]
min_by, max_by, minmax_by
ブロックを評価した結果で比較する
array = %w(a bb ccc)
array.min_by{|str| str.length } # => "a"
array.max_by{|str| str.length } # => "ccc"
array.minmax_by{|str| str.length } # => ["a", "ccc"]
ソート
sort, sort_by
ソートした結果を新しい配列で返す
array = %w(cc a bbb)
# 要素でソート
array.sort # => ["a", "bbb", "cc"]
# 要素の長さでソート1
array.sort {|a, b| a.length <=> b.length } # => ["a", "cc", "bbb"]
# 要素の長さでソート2
array.sort_by { |str| str.length } # => ["a", "cc", "bbb"]
上記の場合、sort_byのほうが高速
sortは比較の度に2つの要素に対してメソッドを呼んでいる。
sort_byは要素ごとにメソッドを1回だけ呼んでいる。