6
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

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

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
6
Help us understand the problem. What are the problem?