Hash#any?
ではHashの全要素の値が false
でも false
が返ってこない
ブロック無しの Hash#any?
を使えば、Hash の全要素の値が false
ならば false
を返してくれるのではないかとイメージしました。
残念ながら Hash#any?
は実装されておらず Enumerable#any?
が呼ばれます。このため、値だけを評価するのでは無く、キーと値のペア配列 自身 を評価するように働きます。
このため、
{a: false, b: false, c: false}.any?
# == [[:a, false], [:b, false], [:c, false]].any?
#=> true
となってしまい、当初にイメージしていた false
が返ってきてくれません。
対策0:Hash#values
を使って値だけの配列を作る(追記)
@Ueno1969 さんコメントのやり方です。
{a: false, b: false, c: false}.values
#=> [false, false, false]
これをメソッドチェーンして Enumerable#any?
を使えば、求めている false
が返りますね。
{a: false, b: false, c: false}.values.any?
#=> false
このやり方が一番キレイだと思います。
同様に Hash#values
から Enumerable#all?
へのメソッドチェーンなども使えますね。
対策1:ブロックで処理
キーと値のペアを評価したかったのではないので、値を呼んで評価しましょう。
{a: false, b: false, c: false}.any? { |k, v| v }
# = [false, false, false]
#=> false
{a: false, b: false, c: true }.any? { |k, v| v }
# = [false, false, true]
#=> true
るりま引用
instance method Enumerable#any?
any? {|item| ... } -> bool
ブロックを伴う場合は、各要素に対してブロックを評価し、すべての結果 が偽である場合に false を返します。ブロックが真を返した時点 で、ただちに true を返します。
例:p [1, 2, 3].any? {|v| v > 3 } # => false p [1, 2, 3].any? {|v| v > 1 } # => true
対策2:モンキーパッチ
モンキーパッチは Ruby のコアライブラリの仕様を書き換えます。require した gem などに影響して、思わぬところで不具合が出るリスクがあります。実務で使うことは避けた方が良いでしょう。
class Hash
alias :__any__? :any?
def any?
self.__any__? { |k, v| v }
end
end
では使ってみましょう。
{a: false, b: false, c: false}.any?
#=> false
{a: false, b: false, c: true }.any?
#=> true
もちろんこれでは any?
にブロックを付けられないので不完全ですが、ひとまずはこれで十分でしょう。
訂正:
冒頭のスクリプトですが、当初は
{a: false, b: false, c: false}.any?
# == [:a, false, :b, false, :c, false].any?
と書いていました。しかし
{a: false, b: false, c: false}.all?
#=> true
なので、 Hash
から Enumerable
を扱うときに、キーと値のペアを作る Hash#to_a
が使われて
{a: false, b: false, c: false}.any?
# == [[:a, false], [:b, false], [:c, false]].any?
と解釈しないとおかしい事が分かります。
訂正いたします。m(_ _)m