Search code examples
arraysrubyhashsum

Sum of hash value inside the array In ruby


I have array like this

data = 
  [
    { :lineItemKey=>57, :sku=>"12GA-RIO",  
      :name=>"12 Gauge", :quantity=>4, :unitPrice=>5.76 },
    { :lineItemKey=>168, :sku=>"22LR-CAS-40-CPRN-50", 
      :name=>"22 Long", :quantity=>2, :unitPrice=>7.6 },
    { :lineItemKey=>57, :sku=>"12GA-RIO", 
      :name=>"12 Gauge", :quantity=>1, :unitPrice=>5.76 }, 
    { :lineItemKey=>236, :sku=>"300BLK-UNWD-CTC-220-BTHP-20",
      :name=>"300 BLK", :quantity=>1, :unitPrice=>31.2 }
  ]

I need to sum the quantity if the sku is same and remove the duplicate. so the output should be like:

data = 
  [
    { :lineItemKey=>57, :sku=>"12GA-RIO", 
      :name=>"12 Gauge", :quantity=>5, :unitPrice=>5.76 },
    { :lineItemKey=>168, :sku=>"22LR-CAS-40-CPRN-50", 
      :name=>"22 Long", :quantity=>2, :unitPrice=>7.6 }, 
    { :lineItemKey=>236, :sku=>"300BLK-UNWD-CTC-220-BTHP-20",
      :name=>"300 BLK", :quantity=>1, :unitPrice=>31.2 }
  ]

Solution

  • Input

    data = 
      [
        { :lineItemKey=>57, :sku=>"12GA-RIO", 
          :name=>"12 Gauge", :quantity=>4, :unitPrice=>5.76 },
        { :lineItemKey=>168, :sku=>"22LR-CAS-40-CPRN-50", 
          :name=>"22 Long", :quantity=>2, :unitPrice=>7.6 },
        { :lineItemKey=>57, :sku=>"12GA-RIO", 
          :name=>"12 Gauge", :quantity=>1, :unitPrice=>5.76 }, 
        { :lineItemKey=>236, :sku=>"300BLK-UNWD-CTC-220-BTHP-20",
          :name=>"300 BLK", :quantity=>1, :unitPrice=>31.2 }
      ]
    

    Code

    p data.group_by { |x| x[:lineItemKey] }
          .values
          .map { |arr| arr.reduce { |h1, h2| h1.merge(h2) { |k, oldv, newv| k.eql?(:quantity) ? oldv += newv : oldv } } }
    

    Output

    [
      { :lineItemKey=>57, :sku=>"12GA-RIO", 
        :name=>"12 Gauge", :quantity=>5, :unitPrice=>5.76 }, 
      { :lineItemKey=>168, :sku=>"22LR-CAS-40-CPRN-50",  
        :name=>"22 Long", :quantity=>2, :unitPrice=>7.6 }, 
      { :lineItemKey=>236, :sku=>"300BLK-UNWD-CTC-220-BTHP-20", 
        :name=>"300 BLK", :quantity=>1, :unitPrice=>31.2 }
    ]