kkir
kkir

Reputation: 37

Output index of hash in array of hashes?

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

Answers (4)

sa77
sa77

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

Cary Swoveland
Cary Swoveland

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

Simple Lime
Simple Lime

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

jdgray
jdgray

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

Related Questions