Sandra Cieseck
Sandra Cieseck

Reputation: 331

Ruby: transform Hash-Keys

I have a Hash:

urls = [{'logs' => 'foo'},{'notifications' => 'bar'}]

The goal is to add a prefix to the keys:

urls = [{'example.com/logs' => 'foo'},{'example.com/notifications' => 'bar'}]

My attempt:

urls.map {|e| e.keys.map { |k| "example.com#{k}" }}

Then I get an array with the desired form of the keys but how can I manipulate the original hash?

Upvotes: 3

Views: 1931

Answers (3)

SRack
SRack

Reputation: 12203

Use transform_keys.

urls = [{'logs' => 'foo'}, {'notifications' => 'bar'}]
urls.map { |hash| hash.transform_keys { |key| "example.com/#{key}" } }
# => [{"example.com/logs"=>"foo"}, {"example.com/notifications"=>"bar"}]

One question: are you best served with an array of hashes here, or would a single hash suit better? For example:

urls = { 'logs' => 'foo', 'notifications' => 'bar' }

Seems a little more sensible a way to store the data. Then, saying you did still need to transform these:

urls.transform_keys { |key| "example.com/#{key}" }
# => {"example.com/logs"=>"foo", "example.com/notifications"=>"bar"}

Or to get from your original array to the hash output:

urls = [{'logs' => 'foo'}, {'notifications' => 'bar'}]
urls.reduce({}, &:merge).transform_keys { |key| "example.com/#{key}" }

# => {"example.com/logs"=>"foo", "example.com/notifications"=>"bar"}

Much easier to work with IMHO :)

Upvotes: 3

lacostenycoder
lacostenycoder

Reputation: 11226

If you don't have access to Hash#transform_keys i.e. Ruby < 2.5.5 this should work:

urls.map{ |h| a = h.to_a; { 'example.com/' + a[0][0] => a[0][1] } }

Upvotes: 0

Sebasti&#225;n Palma
Sebasti&#225;n Palma

Reputation: 33420

If you want to "manually" transform the keys, then you can first iterate over your array of hashes, and then over each object (each hash) map their value to a hash where the key is interpolated with "example.com/", and the value remains the same:

urls.flat_map { |hash| hash.map { |key, value| { "example.com/#{key}" => value } } }
# [{"example.com/logs"=>"foo"}, {"example.com/notifications"=>"bar"}]

Notice urls are being "flat-mapped", otherwise you'd get an arrays of arrays containing hash/es.

If you prefer to simplify that, you can use the built-in method for for transforming the keys in a hash that Ruby has; Hash#transform_keys:

urls.map { |url| url.transform_keys { |key| "example.com/#{key}" } }
# [{"example.com/logs"=>"foo"}, {"example.com/notifications"=>"bar"}]

Upvotes: 6

Related Questions