DevelopmentWeb

Find all the values for a given key in a nested Hash using Ruby

By July 10, 2013 No Comments

On my current project we have a hash named line items.  This contains multiple hashes, and arrays of hashes, that will eventually have a :total key.  You might also find yourself with a similar hash when consuming public APIs.

line_items = {
  item_a: {
    name: "Cookie",
    total: 13
  },
  department_x: {
    item_b: {
      name: "s",
      total: 7
    }
  },
  items: [
    {
      name: "H",
      total: 8
    },
    {
      name: "Q",
      total: 9
    }
  ]
}

An obvious use of this would to calculate a grand total by summing all of the totals.  Not finding exactly what I was looking for online, I wrote this little method to help the calculation by fetching all of the values that have a key :total.

class Hash
  def find_all_values_for(key)
    result = []
    result << self[key]
    self.values.each do |hash_value|
      values = [hash_value] unless hash_value.is_a? Array
      values.each do |value|
        result += value.find_all_values_for(key) if value.is_a? Hash
      end
    end
    result.compact
  end
end

This solution is essentially a depth first search implemented with recursion.  It will return an array of all the values the key points to.

line_items.find_all_values_for(:total)
# => [13, 7, 8, 9] 
line_items.find_all_values_for(:total).sum
# => 37 
line_items.find_all_values_for(:name).sum
# => "CookiesHQ"