I have an array of hashes and each hash needs to be printed out on the same line.
init_cards_j = [
{ init1: [{ num: 6, head: 1 }, { num: 10, head: 1 }] },
{ init2: [{ num: 53, head: 1 }, { num: 60, head: 1 }] },
{ init3: [{ num: 77, head: 5 }] },
{ init4: [{ num: 89, head: 1 }] }
]
I want it to be looked like this:
Card 6: 1 head / Card 10: 1 head
Card 53: 1 head / Card 60: 1 head
Card 77: 1 head
Card 89: 1 haed
I tried below:
init_cards_j.each_index do |index|
init_cards_j[index].values[0].each do |pair|
init_cards_j[index].each do |key, value|
value.each do |pair|
puts "Card #{pair[:num]}: #{pair[:head]} kettle head. / "
end
end
end
end
Which outputs the data as:
Card 6: 1 kettle head. /
Card 10: 1 kettle head. /
Card 6: 1 kettle head. /
Card 10: 1 kettle head. /
Card 53: 1 kettle head. /
Card 60: 1 kettle head. /
Card 53: 1 kettle head. /
Card 60: 1 kettle head. /
Card 77: 5 kettle head. /
Card 89: 1 kettle head. /
I am sorry that my array is so nested as I need to sort the order by num
for each hash, I put them in an array.
Thanks in advance!
CodePudding user response:
You can iterate the hashes in init_cards_j
via each
and for each hash call each_value
to traverse its values. Then, instead of printing every card right away, you can generate an intermediate array via map
and join
the result using your separator string:
init_cards_j.each do |hash|
hash.each_value do |values|
puts values.map { |c| "Card #{c[:num]}: #{c[:head]} head" }.join(' / ')
end
end
But it would be easier to convert the array of hashes to a single hash: (assuming that their keys are unique)
cards = {
init1: [{ num: 6, head: 1 }, { num: 10, head: 1 }],
init2: [{ num: 53, head: 1 }, { num: 60, head: 1 }],
init3: [{ num: 77, head: 5 }],
init4: [{ num: 89, head: 1 }]
}
If you must retain the given structure, you could convert it on the fly:
cards = init_cards_j.inject(&:merge)
This makes the loop a bit simpler:
cards.each_value do |values|
puts values.map { |c| "Card #{c[:num]}: #{c[:head]} head" }.join(' / ')
end
CodePudding user response:
I would recommend @Stefan's first answer, but here is another way to achieve the same result.
We might begin with a helper method, which of course you can test separately:
def print_num_and_head(g)
print "Card %d: %d head" % g.values_at(:num, :head)
end
If
g = {:num=>6, :head=>1})
then
print_num_and_head(g)
displays
Card 6: 1 head
without a line terminator.
We may then write:
init_cards_j.each do |h|
_, (g, *arr) = h.flatten
print_num_and_head(g)
arr.each do |g|
print ' / '
print_num_and_head(g)
end
puts
end
prints
Card 6: 1 head / Card 10: 1 head
Card 53: 1 head / Card 60: 1 head
Card 77: 5 head
Card 89: 1 head
Here I've used Ruby's powerful array#decomposition (a.k.a array disambiguation) syntax to advantage:
If
h = { init1: [{ num: 6, head: 1 }, { num: 10, head: 1 }] }
then
_, (g, *arr) = h.flatten
#=> [:init1, [{:num=>6, :head=>1}, {:num=>10, :head=>1}]]
_ #=> :init1
g #=> {:num=>6, :head=>1}
arr
#=> [{:num=>10, :head=>1}]
I've employed the common convention of representing a block variable with an underscore when it is not used in the block calculation.
See this article for a fuller explanation array decomposition.