ruby - guarantee order of keys in hash after much manipulation -
here's problem. going through these steps below can see how hash keys no longer in order. in below example, keys 0, 2, rather 0,1. , sure larger data set, situation worse. there way can guarantee order of keys in hash?
task:
- if fields has defaults doesn't have, add defaults
- if defaults has key
k
field not have, remove key-value pair keyk
default
test data:
fields = { "0"=>{"field"=>"name", "field_type_id"=>1}, "1"=>{"field"=>"address", "field_type_id"=>2} } defaults = {0=>"name", 1=>"email" }
step 1: find ones in fields not in defaults:
fields_arr = fields.values.collect {|hsh| hsh['field'] } => ["name", "address"] defaults_arr = defaults.values => ["name", "email"] updates = fields_arr + defaults_arr - (fields_arr & defaults_arr) - defaults_arr => ["address"]
step 2: update defaults new fields, key starts last key of defaults:
i = defaults.keys.last.to_i + 1 additions = updates.reduce({}) |acc, n| acc[i] = n += 1 acc end defaults.merge!(additions) => {0=>"name", 1=>"email", 2=>"address"}
step 3: remove defaults no longer exists in fields. (in other words, have remove "email" in example):
defaults => {0=>"name", 1=>"email", 2=>"address"} defaults_arr = defaults.values removals = fields_arr + defaults_arr - (fields_arr & defaults_arr) => ["email"] defaults.delete_if{|_,v| removals.include? v } => {0=>"name", 2=>"address"}
a hash ordered, doesn't mean it's sorted; there's big difference. it's ordered because insertion order of key/value pairs remembered. documentation says:
hashes enumerate values in order corresponding keys inserted.
sorting hash nonsensical; nothing speed access or insertion speed, and, if insist on maintaining sort order in hash modify it, you're wasting cpu time.
think of them if random access devices, such in-memory database when reading/writing records. can jump around without real speed penalty , find things, insert new ones, or update them. having them in sorted order makes no real difference @ point.
if need retrieve keys or associated values in particular order, then, after you're finished modifying hash, extract keys using keys
, order resulting array iterate on or use values_at
or order result of values
:
foo = { 'z' => 26, 'a' => 1 } sorted_keys = foo.keys.sort # => ["a", "z"] foo.values_at(*sorted_keys) # => [1, 26] reverse_sorted_keys = foo.keys.sort.reverse # => ["z", "a"] foo.values_at(*reverse_sorted_keys) # => [26, 1] foo.values.sort # => [1, 26] foo.values.sort.reverse # => [26, 1]
i'd recommend reading "sort hash key, return hash in ruby" , answers more information.
Comments
Post a Comment