It is always nice to do the same thing in a better and quicker way. A problem that occurs quite often in my everyday work is converting a hash to an array of hashes with a different structure.
The problem
Let’s assume that we have a following hash:
hash = { name: 'John', surname: 'Smith', age: '25', city: 'Gdańsk' }
and for a some reason, like external API integration, we need an array of hashes looking like this:
array = [ { name: 'name', content: 'John' }, { name: 'surname', content: 'Smith' }, { name: 'age', content: '25' }, { name: 'city' content: 'Gdańsk' } ]
My previous approach
I used to create a method with an empty array defined and push custom hashes into the array using `each` iterator. Also the method needs to return the array.
def hash_to_array_of_hashes array = [] hash.each do |key, value| array << { name: key.to_s, value: value } end array end
Better solution
`each_with_object` is a less popular method that belongs to `Enumerable` mixin. According to the Ruby 2.2.2 documentation:
Iterates the given block for each element with an arbitrary object given, and returns the initially given object.
each_with_object(obj) { |(*args), memo_obj| ... } → obj
The most tricky part for me was this memo object. Basically you can provide any kind of object and it will be returned. Let’s consider a simple example and create an array of numbers from 1 to 10.
(1..10).each_with_object([]) { |number, memo_array| memo_array << number } => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I also needed an array, but of hashes so I improved the above code:
hash.each_with_object([]) do |(key, value), memo_array| memo_array << { name: key.to_s, content: value } end => [{:name=>"name", :content=>"John"}, {:name=>"surname", :content=>"Smith"}, {:name=>"age", :content=>"25"}, {:name=>"city", :content=>"Gdańsk"}]
and it just did the job.
Summary
It is never late to learn. I enjoy doing things better, in a more clever way.
Have you known `each_with_object` method or maybe you know a better solution for the above problem?