You don't have an array of product IDs and Quantities. You have an array of arrays of integers. The easiest way to deal with this array of arrays of integers is to not have an array of arrays of integers but an Order:
class Product
def to_s; 'Some Product' end
alias_method :inspect, :to_s
end
class LineItem
attr_reader :product, :count
def initialize(product, count)
self.product, self.count = product, count
end
def to_s; "#{count} x #{product}" end
alias_method :inspect, :to_s
private
attr_writer :product, :count
end
class Order
include Enumerable
def initialize(*line_items)
self.line_items = line_items
end
def each(&blk) line_items.each(&blk) end
def items
group_by(&:product).map {|product, line_items| LineItem.new(product, line_items.sum(&:count)) }
end
def to_s; line_items.map(&:to_s).join(', ') end
alias_method :inspect, :to_s
private
attr_accessor :line_items
end
Now, assuming that you receive your data in the form of an Order, instead of an array of arrays of integers, like this:
product1 = Product.new
product4 = Product.new
product5 = Product.new
order = Order.new(
LineItem.new(product1, 10),
LineItem.new(product1, 30),
LineItem.new(product4, 10),
LineItem.new(product4, 100),
LineItem.new(product5, 45)
)
All you need to do is:
order.items
#=> [40 x Some Product, 110 x Some Product, 45 x Some Product]
The bottom line is: Ruby is an object-oriented language, not an array-of-arrays-of-integers-oriented language, if you use rich objects instead of arrays of arrays of integers, your problem will become much simpler.
Note: I used order processing as an example. If your problem domain is warehouse management or something else, there will be a similar solution.