Reputation: 37
This might be a silly question, but I'm struggling with outputting the positions of an array of hashes I have.
If I have an array of hashes, we'll call some_array
, that looks like this:
some_array =
[{:id=>7, :people=>["Bob B", "Jimmy J"], :product=>"product1"},
{:id=>2, :people=>["Sally S"], :product=>"product1"},
{:id=>5, :people=>["Hank H", "Stan C"], :product=>"product2"},
{:id=>3, :people=>["Sue T"], :product=>"product2"},
{:id=>4, :people=>["Anne W"], :product=>"product3"}]
I then iterate though some_array
like so:
some_array.select{|p| p[:product] == "product2"]}.each do |product|
product[:people].join("<br>")
product[:product]
Which outputs like:
Hank K product 2
Stan C
Sue T product 2
How would I go about outputting the index/position of each hash in the array?
Would I be able to do something along the lines of:
some_array.select{|p| p[:product] == "product2"]}.each do |product|
product.index
product[:people].join("<br>")
product[:product]
And get:
2 Hank K product2
Stan C
3 Sue T product2
Thank you!
Upvotes: 0
Views: 297
Reputation: 3603
you can just use each_with_index
and skip the item you don't need
some_array.each_with_index do |product, index|
next if product[:product] != "product2"
index
product[:people].join("<br>")
product[:product]
end
Upvotes: 1
Reputation: 110755
fmt_str_first = "%-4d%-10s%10s"
fmt_str_rest = "#{' '*4}%-10s"
some_array.each_with_index do |h,i|
next unless h[:product] == "product2"
first, *rest = h[:people]
puts fmt_str_first % [i, first, "product2"]
rest.each { |name| puts fmt_str_rest % name }
puts
end
2 Hank H product2
Stan C
3 Sue T product2
See Kernel#sprintf. Note that %-10s
in the format string means that the corresponding entry, a string (s
), is to be left-adjusted (-
) in a field of width 10
. %10s
would cause the entry to be right-adjusted.
Upvotes: 1
Reputation: 11070
In Ruby, you can chain methods on Enumerable
, which allows you to call with_index
before you select
to get the original index of the element:
some_array.each_with_index.select do |element, _|
element[:product] == "product2"
end.each do |product, index|
p [index, product[:people].join("<br />"), product[:product]]
end
# outputs:
# [2, "Hank H<br />Stan C", "product2"]
# [3, "Sue T", "product2"]
While you can call select.with_index
, and it may be tempting to do so, the index won't carry over into the each
, because select
returns the elements that matched and doesn't care about the input. When you call each_with_index
(or each.with_index
), though, you now have a new Enumerable which is each element in your array with its index in that array, and select
ends up returning these new array elements:
some_array.each.with_index.select { |element, _| element[:product] == "product2" }
# => [[{:id=>5, :people=>["Hank H", "Stan C"], :product=>"product2"}, 2],
[{:id=>3, :people=>["Sue T"], :product=>"product2"}, 3]]
Upvotes: 1
Reputation: 1983
You can use each_with_index and format to your use case:
some_array.each_with_index do |product, index|
if product[:product] == "product2"
p index
p product
end
end
Upvotes: 1