Home > Net >  Sum of hash value inside the array In ruby
Sum of hash value inside the array In ruby

Time:01-13

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 }
  ]

CodePudding user response:

data.each_with_object({}) do |g,h|
  h.update(g[:lineItemKey]=>g) do |_k, old_hash, new_hash|
    old_hash.merge(quantity: old_hash[:quantity]   new_hash[:quantity])
  end
end.values
  #=> [
  # {: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}
  # ]

Note that the receiver of values is

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

This uses the form of Hash#update (a.k.a merge!) that employs a block to compute the values of keys that are present in both hashes being merged. Here that block is

do |_k, old_hash, new_hash|
  old_hash.merge(quantity: old_hash[:quantity]   new_hash[:quantity])
end

See the doc for definitions of the three block variables. The underscore preceding k (the common key) is intended tro signal to the reader that it is not used in the block calculation (a common convention which is often just the underscore alone).

CodePudding user response:

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 }
]
  •  Tags:  
  • Related