1

Given that I have these hashes:

h1 = {"a" => { "b" => 1, "c" => {"d" => 2, "e" => 3} } }
h2 = {"a" => { "b" => 1, "c" => nil } }

And I want these results:

h1.multi_all?  # true
h2.multi_all?  # false

How would I implement the multi_all method?

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
Marek Příhoda
  • 11,108
  • 3
  • 39
  • 53

2 Answers2

3
class Hash
  def multi_all? &block
    all? do |key, value|
      if value.is_a?(Hash)
        value.multi_all?(&block)
      elsif block == nil
        value
      else
        block[key, value]
      end
    end
  end
end
robbrit
  • 17,560
  • 4
  • 48
  • 68
  • Thanks, but try this: `p h2.multi_all? { |k, v| v > 0 }`. It raises undefined method exception – Marek Příhoda Dec 13 '11 at 20:26
  • Does it say undefined method exception for NilClass? It's because you have a nil value in h2 which does not have a > method. – robbrit Dec 13 '11 at 20:29
  • sorry, it says `undefined method `>' for nil:NilClass (NoMethodError)` – Marek Příhoda Dec 13 '11 at 20:32
  • Yeah that's because you have `"c" => nil` in your hash. If you want to use Hash#all? or this new version, all the elements within the Hash must be compatible with the block you pass in. – robbrit Dec 13 '11 at 20:52
  • you're right, given `h3 = {"a" => nil }; p h3.all? { |k, v| v > 0 }`, I, of course, get the same error, so it's a consistent behaviour – Marek Příhoda Dec 13 '11 at 20:59
  • Yeah it's supposed to do that. Doing `nil > 0` doesn't make sense. – robbrit Dec 13 '11 at 21:14
2
class Hash
  def values_r # recursive values
     self.values.map do |x|
       x.is_a?(Hash) ? x.values_r : x
     end
  end
end

h1.values_r.flatten.all?

PS: do you know that all? method also accepts a block?

zed_0xff
  • 32,417
  • 7
  • 53
  • 72