branquito branquito - 5 months ago 9
Ruby Question

traverse array of hashes in ruby (jekyll)

I am writing a plugin for Jekyll so that I can compare some data on products,
and I am returning array of hashes like so to be available in my template:

data = [{"current"=>"0.4mA", "power"=>"15w"}, {"current"=>"1A", "power"=>"5w"}]


But now, when I traverse them using
liquid
:

<table>
{% for h in data %}
<tr>
{% for p in h %}
<td>{{ p[0] }}</td>
<td>{{ p[1] }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>


I am not able to list properties side by side, as I am passing through hashes
one at a time, so I end up having them one below the other instead.

What should I do from plugin to prepare the data the other way around, so that I would be
able to do what I want in my template?

EDIT:

So to clear up a bit, how to obtain following structure from the above array
of hashes using pure ruby?:

p1['current'] = '0.4mA'
p1['power'] = '15w'
... *may have more of these, depending on number of key:value pairs in the hash
p1['...'] = '...'

p2['current'] = '1A'
p2['power'] = '5w'
... *may have more of these, depending on number of key:value pairs in the hash
p2['...'] = '...'

Answer

If you want the properties displayed in rows (eg, one row for 'current', one row for 'power', etc) and you don't want to make any changes to the display template, you can transform your data hash in Ruby like this - one of the following (maybe both) should work with your template:

If you know that every hash in data will have all the keys, you can take the keys from the first element:

keys = data[0].keys

OR if hashes in data might omit keys if the data is not meaningful, you can get all the distinct keys in data

keys = data.map(&:keys).flatten.uniq

new_data_array = keys.map { |a| data.map { |d| d[a] } }
=> [["0.4mA", "1A"], ["15w", "5w"]]

new_data_hash = Hash[keys.map {|a| [a, data.map { |d| d[a] }] }]
=> {"current"=>["0.4mA", "1A"], "power"=>["15w", "5w"]}

Here's how to bypass the data array and just get the values straight from h1 and h2 in one line:

Hash[(h1.keys & h2.keys).map {|a| [a, [h1, h2].map { |d| d[a] }] }]
=> {"current"=>["0.4mA", "1A"], "power"=>["15w", "5w"]}

(h1.keys & h2.keys).map {|a| [h1, h2].map { |d| d[a] } }
=> [["0.4mA", "1A"], ["15w", "5w"]]