1

Suppose I have the following class, product.rb:

require 'yaml'

class Product
    attr_accessor :id, :price

    def initialize args = {}
        options = {:id => "", :price => 0}.merge(args)
        self.id, self.price = options[:id], options[:price]
    end

    def inspect
        self.to_yaml        
    end
end

And the following example program, example.rb:

require_relative 'product'

products = Array.new

(1..5).each do |n| # Create 5 products with random id and price
    products << Product.new(
        :id => rand(1..5),
        :price => rand(10..50))
end

products.each { |p| puts p.inspect }

Example output from running example.rb:

C:\>ruby example.rb
--- !ruby/object:Product
id: 3
price: 48
--- !ruby/object:Product
id: 2
price: 47
--- !ruby/object:Product
id: 5
price: 32
--- !ruby/object:Product
id: 5
price: 49
--- !ruby/object:Product
id: 3
price: 33

The result is an array of objects of type Product, with duplicate ids.

How can I create a hash with id as the key and the sum of price as the value?

Example of desired result:

{ "2" => 47, "3" => 81, "5" => 81 } # { id => sum of price }
2
  • Is the hash supposed to be ordered by id? Commented Jan 2, 2017 at 14:57
  • Ordering by id is not necessary in this particular case, but it would be a nice bonus. I can always sort the resulting hash after it has been created. Commented Jan 3, 2017 at 7:28

3 Answers 3

4

You can use each_with_object to inject a Hash with default value of 0, like this:

products.each_with_object(Hash.new(0)) { |p, result| result[p.id] += p.price }

Sign up to request clarification or add additional context in comments.

1 Comment

Perfect, I wasn't aware of each_with_object and was fumbling around with map and lambdas. Ruby being Ruby, I knew there was probably an easier way.
1
products = Array.new
sum_hash = Hash.new(0) # new hash with default 0 value

(1..5).each do |n| # Create 5 products with random id and price
  id = rand(1..5)
  price = rand(10..50)

  sum_hash[id] += price

  products << Product.new(
    :id => id,
    :price => price)
end

products.each { |p| puts p.inspect }    

Comments

0

Another possibility would be to use group_by :

products.group_by(&:id)
        .map{|id, ps| [id, ps.map(&:price).inject(:+)] }
        .to_h

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.