Rubyのmodule Enumerableを体験してみた

## 背景
**「Rubyのmodule Enumerableは便利なメソッドが盛りだくさんだよ」**
という声を聞き、実際にどんなメソッドがあるのかを「体験」してみました。
自分の勉強として残します。
※メソッドの数が多いので、随時更新してます

## 環境
Ruby 3.2

## module Enumerableの公式リファレンスはこちら
https://docs.ruby-lang.org/ja/latest/class/Enumerable.html

## module Enumerableのメソッドたち

### [`all?`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html#I_ALL--3F) 
>すべての要素が真である場合に true を返します。偽である要素があれば、ただちに false を返します。
>ブロックを伴う場合は、各要素に対してブロックを評価し、すべての結果が真である場合に true を返します。ブロックが偽を返した時点で、ただちに false を返します。

※上記は、公式リファレンスから引用しています

#### `all?` の活用事例
```ruby
# 5教科の点数を配列として定義
scores = [100, 80, 59, 70, 67]

# 合否基準を60点とする
target_score = 60

# 1教科でも60点未満なら不合格
scores.all? {|score| score >= target_score}
=> false
# 全教科が60点以上なら合格
scores = [100, 80, 60, 70, 67]
scores.all? {|score| score >= target_score}
=> true
```

***

### [`any?`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html#I_ANY--3F)
>すべての要素が偽である場合に false を返します。真である要素があれば、ただちに true を返します。
>ブロックを伴う場合は、各要素に対してブロックを評価し、すべての結果が偽である場合に false を返します。ブロックが真を返した時点で、ただちに true を返します。

#### `any?` の活用事例
```ruby
# 4つの選択肢を持つ質問があり
# 3番目が選ばれると、以下のような配列を返すとする
answers = [false, false, true, false]

# いずれかの選択肢が選ばれていると ture を返す
answers.any? {|answer| answer}
=> true

# いずれも選択されていなければ false を返す
answers = [false, false, false, false]
answers.any? {|answer| answer}
=> false
```

***

### [`chain`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html#I_CHAIN)
>自身と enums 引数を続けて繰り返す Enumerator::Chain を返します。

#### `chain` の活用事例

※調査中

***

### [`chunk`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html#I_CHUNK)

>要素を前から順にブロックで評価し、その結果によって要素をチャンクに分けた(グループ化した)要素を持つ Enumerator を返します。
>ブロックの評価値が同じ値が続くものを一つのチャンクとして取り扱います。すなわち、ブロックの評価値が一つ前と異なる所でチャンクが区切られます。
>返り値の Enumerator は各チャンクのブロック評価値と各チャンクの要素を持つ配列のペアを各要素とします。そのため、eachだと以下のようになります。

#### `chunk` の活用事例
```ruby
# 先週の天気を配列で定義
weather_last_week = ["晴れ", "曇り", "晴れ", "雨", "晴れ", "晴れ", "晴れ"]

# 同じ天気が続いた日数を出力する
weather_last_week.chunk { |x| x }.map { |key, values| [key, values.count] }.
to_h
=> {"晴れ"=>3, "曇り"=>1, "雨"=>1}
```

***

### [`chunk_while`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html#I_CHUNK_WHILE)

>要素を前から順にブロックで評価し、その結果によって要素をチャンクに分けた(グループ化した)要素を持つEnumerator を返します。
>隣り合う値をブロックパラメータ elt_before、elt_after に渡し、ブロックの評価値が偽になる所でチャンクを区切ります。
>ブロックは self の長さ - 1 回呼び出されます。

#### `chunk_while` の活用事例
```ruby
# 書籍で校正が必要なページ数を配列で定義する
specific_pages = [1, 2, 3, 5, 6, 9]

# 該当ページ数の表記を、範囲表現できるようにする
specific_pages.chunk_while {|i, j| i+1 == j }.map {|a| a.length < 3 ? a 
: "#{a.first}〜#{a.last}" }.join(",")
=> "1〜3,5,6,9"
```

***

### [`collect`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html#I_COLLECT)

>各要素に対してブロックを評価した結果を全て含む配列を返します。
>ブロックを省略した場合は Enumerator を返します。

#### `collect` の活用事例
```ruby
# 配列を用意
numbers = [2, 9, 4, 3]

# 要素を2倍した配列を返す
numbers.collect {|n| n * 2}
=> [4, 18, 8, 6]
```

***

### [`collect_concat`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html#I_COLLECT_CONCAT)

>各要素をブロックに渡し、その返り値を連結した配列を返します。
>ブロックの返り値は基本的に配列を返すべきです。
>ブロックを省略した場合は Enumerator を返します。

#### `collect_concat` の活用事例
```ruby
# 多次元の配列を用意
numbers = [[2, 9], [4, 3, 1, 2]]

# 1次元配列にし、要素を2倍する
numbers.collect_concat {|arr| arr.map {|n| n * 2}}
=> [4, 18, 8, 6, 2, 4]

# collectだけだとこうなる
numbers.collect {|n| n * 2}
=> [[2, 9, 2, 9], [4, 3, 1, 2, 4, 3, 1, 2]]
```

***

### [`compact`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html#I_COMPACT)

>self から nil を取り除いた配列を生成して返します。

#### `compact` の活用事例
```ruby
# 配列を定義
numbers = [1, 2, 3, nil, 5]

# nilを排除する
numbers.compact
=> [1, 2, 3, 5]

# 空文字は排除されない
users = ["Tom", "Alice", "", "John"]
users.compact
=> ["Tom", "Alice", "", "John"]
```

***

### [`count`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html#I_COUNT)

>レシーバの要素数を返します。
>引数を指定しない場合は、レシーバの要素数を返します。このとき、要素数を一つずつカウントします。
>引数を一つ指定した場合は、レシーバの要素のうち引数に一致するものの個数をカウントして返します(一致は == で判定します)。
>ブロックを指定した場合は、ブロックを評価して真になった要素の個数をカウントして返します。

#### `count` の活用事例
```ruby
# 先週の天気を配列で定義
weather_last_week = ["晴れ", "曇り", "晴れ", "雨", "晴れ", "晴れ", "晴れ"]

# 晴れだった日の数を出力
weather_last_week.count { |weather| weather == "晴れ" }
=> 5
```

***

### [`cycle`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html#I_CYCLE)

>Enumerable オブジェクトの各要素を n 回 or 無限回(n=nil)繰り返しブロックを呼びだします。
>n に 0 もしくは負の値を渡した場合は何もしません。繰り返しが最後まで終了した場合(つまりbreakなどで中断しなかった場合) は nil を返します。このメソッドは内部の配列に各要素を保存しておくため、一度 Enumerable の終端に到達した後に自分自身を変更してもこのメソッドの動作に影響を与えません。

#### `cycle` の活用事例
```ruby
# 配列を定義
array = ["a", "b", "c"]

# ブロックを3回呼び出す
array.cycle(3) {|n| print n}
=> abcabcabc
```
ん〜　よい使い道がわからん。。。

***

### [`detect`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html#I_DETECT)

>要素に対してブロックを評価した値が真になった最初の要素を返します。
>真になる要素が見つからず、ifnone も指定されていないときは nil を返します。真になる要素が見つからず、ifnone が指定されているときは ifnone を call した結果を返します。

#### `detect` の活用事例
```ruby
# ユーザ情報を定義
users = [{name: "Bob", age: 20}, {name: "Tom", age: 21}, {name: "Alice", age: 18}]

# 特定の名前に合致するユーザの年齢を表示
users.detect {|user| user[:name] == "Bob"}[:age]
=> 20
```

***

### [`drop`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html#I_DROP)

>Enumerable オブジェクトの先頭の n 要素を捨てて、残りの要素を配列として返します。

#### `drop` の活用事例
```ruby
# Enumerableオブジェクトを定義
e = [1, 3, 6, 2, 5].each

# 要素をソートし、さらに先頭の3つの要素を削除する
e.sort.drop(3)
=> [5, 6]
```

***

### [`drop_while`](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html#I_DROP_WHILE)

>ブロックを評価して最初に偽となった要素の手前の要素まで捨て、残りの要素を配列として返します。
>ブロックを指定しなかった場合は、Enumerator を返します。

#### `drop_while` の活用事例
```ruby
# ユーザ情報を定義
users = [{name: "Bob", age: 20}, {name: "Tom", age: 21}, {name: "Alice", age: 18}, {:name=>"John", :age=>30}]

# 20歳未満のユーザが見つかったら、それ以降のユーザ情報だけを出力する
users.drop_while {|user| user[:age] >= 20}
=> [{:name=>"Alice", :age=>18}, {:name=>"John", :age=>30}]
```