absessive absessive - 6 months ago 18
Ruby Question

Sort Ruby Hash by order in array of keys

I have a hash:

sample = { bar: 200, foo: 100, baz: 100 }


How do I sort
sample
using the order of keys in
sort_order
:

sort_order = [:foo, :bar, :baz, :qux, :quux]


Expected result:

sample #=> { foo: 100, bar: 200, baz: 100 }


All I can come up with is

new_hash = {}
sort_order.each{|k| new_hash[k] = sample[k] unless sample[k].nil? }
sample = new_hash


There's got to be a better way. Hints?

Keys without values should not be present, i.e. number of keys remain the same, which isn't the case with Sort Hash Keys based on order of same keys in array

Answer

The code below does this. Note that I used has_key? because you want the output hash to contain all the keys in the input hash, even if their values are nil.

#!/usr/bin/env ruby

def sorted_hash(input_hash, key_sort_order)
  new_hash = {}
  key_sort_order.each do |key|
    if input_hash.has_key?(key)
      new_hash[key] = input_hash[key]
    end
  end
  new_hash
end

sort_order = [:foo, :bar, :baz, :qux, :quux]
sample = { bar: 200, foo: 100, baz: 100 }

puts sorted_hash(sample, sort_order)
# Outputs: {:foo=>100, :bar=>200, :baz=>100}

A simplification is to use each_with_object:

def sorted_hash_two(input_hash, key_sort_order)
  key_sort_order.each_with_object({}) do |key, result_hash|
    if input_hash.has_key?(key)
      result_hash[key] = input_hash[key]
    end
  end
end

puts sorted_hash_two(sample, sort_order)
# Outputs: {:foo=>100, :bar=>200, :baz=>100}
Comments