[Ruby] 便利な組み込みクラスのメソッド達(Enumerable編)

  • 191
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

概要

パーフェクトRubyを読んでいて便利だと思ったもの一覧です。

Array編
http://qiita.com/kidachi_/items/e9cb26c4e6cb36b70a1c
Hash編
http://qiita.com/kidachi_/items/651b5b5580be40ad047e
String編
http://qiita.com/kidachi_/items/7b355eb355b2d1390cf5

Enumerable

ArrayやHash、Rangeなど、「オブジェクトの集まり」を表現するクラスには
Enumerableがincludeされており、それら全てのクラスで活用できる。

繰り返し処理

each_with_index

配列のkeyとvalueを両方繰り返す。

> %w(Ruby Python Java).each_with_index do |value, key|
>   puts "#{key}: #{value}"
> end
0: Ruby
1: Python
2: Java

reverse

末尾から順に繰り返す。

> %w(Ruby Python Java).reverse { |val| puts val }
=> ["Java", "Python", "Ruby"]

each_slice

要素をn個ずつ区切って繰り返す。

> %w(Ruby Python Java C Smalltalk Brainfuck).each_slice 2 do |a, b|
>   p [a, b]
> end
["Ruby", "Python"]
["Java", "C"]
["Smalltalk", "Brainfuck"]

> %w(Ruby Python Java C Smalltalk Brainfuck).each_slice 4 do |a, b, c, d|
>   p [a, b, c, d]
> end
["Ruby", "Python", "Java", "C"]
["Smalltalk", "Brainfuck", nil, nil]    # 帳尻が合わなかった部分はnil

each_cons

n個の連続した要素を1つずつずらしながら繰り返す

> %w(Ruby Python Java C Smalltalk Brainfuck).each_cons 2 do |a, b|
>   p [a, b]
> end
["Ruby", "Python"]
["Python", "Java"]
["Java", "C"]
["C", "Smalltalk"]
["Smalltalk", "Brainfuck"]

評価結果を配列で返却

map

元の配列の各要素を変換して、新しい配列をつくる

> %w(Ruby Python Java).map { |s| s.upcase }
=> ["RUBY", "PYTHON", "JAVA"]

※eachとの比較

> %w(Ruby Python Java).each {|s| p s.upcase}
"RUBY"
"PYTHON"
"JAVA"
=> ["Ruby", "Python", "Java"]

eachは、戻り値には変更はない。

条件確認

all?

配列の要素が全て真であればtrueを返す。

> [true, true, true].all?
=> true
> [true, true, false].all?
=> false

none?

配列の要素が全て偽であればtrueを返す。

> [false, false, false].none?
=> true
> [true, true, false].none?
=> false

any?

配列の要素のうち一つでも真であればtrueを返す。

> [true, true, false].any?
=> true
> [false, false, false].any?
=> false

one?

配列の要素のうち一つだけ真であればtrueを返す。

> [false, false, true].one?
=> true
> [false, false, false].one?
=> false
> [false, true, true].one?
=> false

条件確認*ブロック

all?, none?, any?, one?はそれぞれブロックを渡す事が出来る。

# 要素が全て整数ならtrue
> [1, 10, 100].all? {|v| v.is_a?(Integer)}
=> true
# 要素が全て文字列ならtrue
> [1, 10, 100].all? {|v| v.is_a?(String)}
=> false
> ["Ruby", "Python", "Java"].all? {|v| v.is_a?(String)}
=> true

部分的な要素の取得

grep

各要素に対してgrepをかけ、マッチする要素を取得する。

# 正規表現にマッチする要素を取得
> %w(Ruby Python Java).grep(/y/)
=> ["Ruby", "Python"]

# 指定の型にマッチする要素を取得
> ["Ruby", "Python", "Java", 1, 10, 100].grep(String)
=> ["Ruby", "Python", "Java"]
> ["Ruby", "Python", "Java", 1, 10, 100].grep(Integer)
=> [1, 10, 100]

detect

戻り値が最初に真になった要素を取得

> %w(Ruby Python Java C Smalltalk Brainfuck).detect { |s| s.include?("y") }
=> "Ruby"

select

戻り値が真になった要素を全て取得。

> %w(Ruby Python Java C Smalltalk Brainfuck).select { |s| s.include?("y") }
=> ["Ruby", "Python"]

reject

戻り値が真になった要素以外を全て取得。

> %w(Ruby Python Java C Smalltalk Brainfuck).reject { |s| s.include?("y") }
=> ["Java", "C", "Smalltalk", "Brainfuck"]

take

先頭から任意の数の要素を取得。

> %w(Ruby Python Java C Smalltalk Brainfuck).take(3)
=> ["Ruby", "Python", "Java"]

drop

先頭から任意の数の要素をスキップしたものを取得。

> %w(Ruby Python Java C Smalltalk Brainfuck).drop(3)
=> ["C", "Smalltalk", "Brainfuck"]

take_while

ブロックが最初に偽を返すまでの要素を取得。

> %w(Ruby Python Java C Smalltalk Brainfuck).take_while { |s| s.include?("y") }
=> ["Ruby", "Python"]

drop_while

ブロックが最初に偽を返してからそれより後の要素を取得。

> %w(Ruby Python Java C Smalltalk Brainfuck).drop_while { |s| s.include?("y") }
=> ["Java", "C", "Smalltalk", "Brainfuck"]

畳み込み演算

inject

直前のブロックの戻り値が入った変数と、現在の要素が入った変数二つを利用して演算できる。

> [1, 2, 3, 4].inject(0) { |result, num| result + num }
=> 10    # 0 +1 + 2 + 3 + 4

第一引数には初期値(上記では0)を設定可能。
初期値を省略すると、先頭の要素が初期値として用いられる。

> [1, 2, 3, 4].inject { |result, num| result + num }
=> 10    # 1 + 2 + 3 + 4

繰り返しの度に呼び出すメソッドをシンボルで受け取ることも可能。

> [1, 2, 3, 4].inject(:+)
=> 10
> [1, 2, 3, 4].inject(:*)
=> 24

繰り返しとオブジェクトの更新

each_with_object

要素を繰り返しながら、オブジェクトを更新していき、最終的に行き着いた値が戻り値となる。
引数には、初期値となるオブジェクトを渡す。

> %w(Ruby Python Java).each_with_object({}) do |name, result|
>   p result
>   result[name] = name.length
> end
{}
{"Ruby"=>4}
{"Ruby"=>4, "Python"=>6}
=> {"Ruby"=>4, "Python"=>6, "Java"=>4}

要素のグルーピング

group_by

特定の条件に基づいて要素をグルーピングする。
ブロックを評価した結果がkeyとなるハッシュが返却される。

> ["Ruby", 1.0, "Python", 1000, 2.5, "Java"].group_by { |v| v.class }
=> {String=>["Ruby", "Python", "Java"], Float=>[1.0, 2.5], Fixnum=>[1000]}

partition

ブロックの戻り値が真か偽かによって二つのグループに分けた、新しい配列を返却する。

> ["Ruby", 1.0, "Python", 1000, 2.5, "Java"].partition { |v| v.is_a?(String) }
=> [["Ruby", "Python", "Java"], [1.0, 1000, 2.5]]

最小値と最大値

min, max, minmax

> range = (1..5)
> range.max
=> 5
> range.min
=> 1
> range.minmax
=> [1, 5]

min_by, max_by, minmax_by

ブロックで評価した結果の値で比較する。
(「何の最小値/最大値か」を決める事が出来る)

> lang = %w(Ruby Python Java C)
> lang.min_by { |s| s.length }
=> "C"
> lang.max_by { |s| s.length }
=> "Python"
> lang.minmax_by { |s| s.length }
=> ["C", "Python"]

ソート

sort, sort_by

> lang = %w(Ruby Python Java C)
# アルファベット順
> lang.sort
=> ["C", "Java", "Python", "Ruby"]
# 要素の長さ(1)
> lang.sort { |a, b| a.length <=> b.length }
=> ["C", "Java", "Ruby", "Python"]
# 要素の長さ(2)
> lang.sort_by { |str| str.length }
=> ["C", "Java", "Ruby", "Python"]

sort_byは、各要素に対して1度しかメソッド呼び出し(今回は.length)を行わないため、sortより高速。