Kepoor Hampond Kepoor Hampond - 15 days ago 6
Ruby Question

How to tell if there are other keys in a hash other than specified ones?

Say I have a hash:

a = {b: "asdfgh", c: "qwerty", d: "dvorak"}


And I want to be able to tell if there are keys other than the ones I specify in it, something like this:

a.has_other_keys?(:b, :c, :d)
=> false
a.has_other_keys?(:c, :d)
=> true


But I don't want it to return false if there are LESS keys than specified:

a.has_other_keys?(:b, :c, :d, :e)
=> true


Is there an easy way to do this in ruby?

Answer

Rails has an except/except! method that returns the hash with those keys removed. If you're already using Rails, You can use it

class Hash
  # Returns a hash that includes everything but the given keys.
  #   hash = { a: true, b: false, c: nil}
  #   hash.except(:c) # => { a: true, b: false}
  #   hash # => { a: true, b: false, c: nil}
  #
  # This is useful for limiting a set of parameters to everything but a few known toggles:
  #   @person.update(params[:person].except(:admin))
  def except(*keys)
    dup.except!(*keys)
  end

  # Replaces the hash without the given keys.
  #   hash = { a: true, b: false, c: nil}
  #   hash.except!(:c) # => { a: true, b: false}
  #   hash # => { a: true, b: false }
  def except!(*keys)
    keys.each { |key| delete(key) }
    self
  end
end

Using above you can do:

bundle :002 >    a = {b: "asdfgh", c: "qwerty", d: "dvorak"}
 => {:b=>"asdfgh", :c=>"qwerty", :d=>"dvorak"}
bundle :006 >  a.except(:b)
 => {:c=>"qwerty", :d=>"dvorak"}
bundle :007 >  a.except(:b).length
 => 2
bundle :008 >  a.except(:b, :c, :d, :e).length
 => 0

In plain Ruby, You can do something like following:

2.2.2 :010 >  a.select{|x| ![:b, :c, :d, :e].include?(x)}
 => {}
2.2.2 :011 >  a.select{|x| ![:b, :c, :d, :e].include?(x)}.length
 => 0