こんにちは。はるぐちです。
Enumerable
モジュールってご存知でしょうか。そうArrayとかHashとかにインクルードされている便利なやつ。
これのおかげで反復処理がスムーズにできると言っても過言ではないEnumerable
モジュールですが、メソッドを全部知っているわけではないなーと思って1記事1メソッドでツアーをすることにしました。
ちゃんとした仕様の説明はRubyリファレンスマニュアル(以下るりま)をみてください。僕は雑に紹介していきます。
all?メソッド
module Enumerable (Ruby 3.1 リファレンスマニュアル)
all?
メソッドは各要素を調べて、真偽値を返すメソッドです。
すべての要素が真である場合はtrue
、1つでも偽である場合はfalse
を返します。
言葉だけではイメージがつかないこともあると思うので、早速irb
で遊んでみます。
irbで挙動の確認
Ruby3.1で確認しています。
引数なしの場合
引数なしの場合は各要素を真偽値に変換します。
Rubyの場合はnil
かfalse
の場合はfalse
になり、それ以外はtrue
に変換されます。
[true, false, true].all? => false [0, 'foo', nil].all? => false
基本的にrangeオブジェクトやhashオブジェクトに対して引数なしのall?
メソッドを呼び出すのはあまり意味がなさそうです。
# なんでもtrueになる (1..3).all? # 1も2も3もtrueなので返り値はtrue => true {a: 1, b: nil}.all? => true
余談ですが、ハッシュのvalueに対してすべての値がtrueか確認したい時はHash#values
メソッドを使って配列に変換するのが良さそうだと思いました。
# 配列に変換 valueだけ取り出す {a: 1, b: false}.values => [1, false] {a: 1, b: false}.values.all? => false
引数ありの場合
引数あり(ブロックなし)の場合は引数に対して===
メソッドを呼び出し各要素と比較します。
===
メソッドの説明は大変なので割愛したい。(挙動がたくさんあって説明しきれないので、、、😅)
class Object (Ruby 3.1 リファレンスマニュアル)
[1, 2, 3].all?(Integer) => true [1.2, 2, 3].all?(Integer) => true ['foo', 'bar', 'baz'].all?(/\w+/) => true ['foo', 'bar', ''].all?(/\w+/) => false
これだけだとイメージしにくい方は以下にイメージ図を参考にしてください。
# イメージ図 [1.2, 2, 3].all?(Integer) の場合 # 各要素に対して順番に 引数 === 要素 を実行していく Integer === 1.2 false Integer === 2 true Integer === 3 true [false, true, true].all? => false
実際には1つでもfalseな要素があった場合はそれ以降の要素は確認されずにfalseが返されるみたいなのでこれはあくまでもイメージと思ってください。
ブロックありの場合
もう少し詳細に条件を絞り込みたい場合はブロック付きでメソッドを呼び出します。
ブロックパラメータは各要素で、ブロックの中でbooleanを返すような条件式を記述します。
# すべて3以上かどうかを調べる (2..5).all? { |v| v >= 3} => false # すべての要素が偶数かどうか調べる [2, 4, 6, 8].all(&:even?) # 全員成人かどうか調べる users = [ {name: 'taro', age: 40}, {name: 'jiro', age: 30}, {name: 'saburo', age: 20} ] users.all? { |hash| hash[:age] >= 20 } => true
ブロックを用いる場合はHash
でも使い道がありそうです。
{a: 1, b: 2}.all? { |k, v| Integer === v } => true {a: 1, b: 2.0}.all? { |k, v| Integer === v } => false
まぁ、この例だったら配列に変換したほうがよさそうではありますね😅
引数とブロックを与えた場合
引数とブロックを与えた場合はどちらが優先されるのでしょうか?るりまには記述が見当たらなかったので自分で調べていきます。
[1, 2, 3].all?(Integer) { |v| v >= 2 } warning: given block not used true
ご覧の通り引数が優先されるみたいです。
warningが出てるので、ひょっとしたらall?
メソッドの話ではなく引数とブロックが両立しないブロック付きメソッドの共通の仕様なのか?(未検証)
まとめ
雑にまとめます。
all?
メソッドは各要素がすべて真ならtrue
、そうでないならfalse
を返すメソッド- 引数ありの場合は
引数 === 要素
で検証 - ブロック付きの場合
- ブロックパラメータ: 各要素
- ブロックの中にはbooleanが返るような式を記述