7
6

More than 5 years have passed since last update.

Hashで全要素の値がfalseであることを確かめるには

Last updated at Posted at 2014-08-07

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

instance method Enumerable#any?

対策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

7
6
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6