ある日のこと。Rubyのコードを読んでいると配列の要素が特定の値を含んでいるかどうかの判定にinclude?
を使っている箇所とany?
を使っている箇所があることに気づきました。
lst = [1,2,3,4,5] puts lst.any?(1) # true puts lst.include?(1) # true
たしかに、どちらを使っても得られる結果は同じです。しかし「配列が特定の値を含んでいるか」という命題に対して、直感的なインターフェースなのはinclude?
でしょう。わざわざany?
を使う必要性は感じません。
include?とany?の違い
include?
は引数に値を指定することしかできませんが、any?
はブロックを指定することができます。
puts [1,2,3,4,5].any? { |n| n == 4 } # true
またany?
はArray
クラスに実装されているメソッドではなく、Enumerable
に実装されているためEnumerable
を継承している
- Array
- Hash
- Range
- Set
などで使用することができます。
require 'set' array_ = [1,2,3,4,5].any? { |n| n == 4 } # true hash_ = { a: 1, b: 2, c: 3 }.any? { |_k, v| v == 2 } # true range_ = (1..10).any? { |n| n == 5 } # true set_ = Set[1,2,3,4,5].any? { |n| n == 3 } # true
ただし、ブロック引数を取れる分、内部での判定が複雑になるためinclude?
と比べると、どのケースでも実行速度が劣ります。
bench_mark.rb
require 'benchmark' big_array = (1..10000).to_a Benchmark.bm do |x| x.report('[any?] 最小値の探索') { big_array.any? { |n| n == 1 } } x.report('[include?] 最小値の探索') { big_array.include?(1) } x.report('[any?] 中央値の探索') { big_array.any? { |n| n == 5000 } } x.report('[include?] 中央値の探索') { big_array.include?(5000) } x.report('[any?] 最大値の探索') { big_array.any? { |n| n == 10000 } } x.report('[include?] 最大値の探索') { big_array.include?(10000) } end
結果
> $ ruby array_bench.rb user system total real [any?] 最小値の探索 0.000004 0.000004 0.000008 ( 0.000001) [include?] 最小値の探索 0.000001 0.000001 0.000002 ( 0.000001) [any?] 中央値の探索 0.000141 0.000000 0.000141 ( 0.000141) [include?] 中央値の探索 0.000019 0.000000 0.000019 ( 0.000019) [any?] 最大値の探索 0.000275 0.000000 0.000275 ( 0.000276) [include?] 最大値の探索 0.000038 0.000000 0.000038 ( 0.000038)
結論
「配列が特定の値を含んでいるか」という場合なら脳死でinclude?
で良いかと思います。
include?
が使えない配列以外の値、配列が含むデータの構造が複雑、条件式が==
ではない場合などではany?
を使った方が良いでしょう。
any?を使った方が良いケース
users = [ { id: 1, name: 'satou', age: 30 }, { id: 2, name: 'tanaka', age: 45 }, { id: 3, name: 'takahashi', age: 21 }, { id: 4, name: 'suzuki', age: 28 }, ] over_40_user_exist = users.any? { |user| user[:age] >= 40 } puts over_40_user_exist # true