# Sum the Product of Two Fields

**URL:** <https://www.ruby-forum.com/t/sum-the-product-of-two-fields/129505>\
**Category:** Rails\
**Created:** [February 19, 2008, 4:34am UTC](https://www.ruby-forum.com/t/sum-the-product-of-two-fields/129505 "2008-02-19T04:34:55Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![rwkreutzer](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/b2d939/32.png) [@rwkreutzer](https://www.ruby-forum.com/u/rwkreutzer)\
**Post date:** [February 19, 2008, 4:34am UTC](https://www.ruby-forum.com/t/sum-the-product-of-two-fields/129505/1 "2008-02-19T04:34:55Z")

</div>

I have two MySQL tables, Orders and Line\_items. Orders has many  
line\_items. The line\_item table has a quantity field and an item\_price  
field. In order.rb, I want to get the total price of the order. I try

def total\_price  
self.line\_items.sum { |li| li.quantity \* li.item\_price}  
end

and get "Wrong number of argument (1 for 2)

def total\_price  
self.line\_items.each { |li| tpsum += (li.quantity \* li.item\_price)}  
tpsum  
end

“you have a nil item when you didn’t expect it. you might have expected  
an array…”

def total\_price  
self.line\_items.each do |li|  
tpsum = tpsum + (li.quantity \* li.item\_price)  
end  
tpsum  
end

same error - nil when you didn’t expect it.

If I do

self.line\_items.sum(:quantity)

I get an answer. That makes me think that I can treat line\_items like  
an array. How can I sum the product of two fields? Thanks.

---

<div class="post-metadata">

**Author:** ![rwkreutzer](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/b2d939/32.png) [@rwkreutzer](https://www.ruby-forum.com/u/rwkreutzer)\
**Post date:** [February 19, 2008, 4:58am UTC](https://www.ruby-forum.com/t/sum-the-product-of-two-fields/129505/2 "2008-02-19T04:58:54Z")

</div>

You might prefer to use inject.

self.line\_items.inject{|a, li| a += li.quantity \* li.price}

---

<div class="post-metadata">

**Author:** ![rwkreutzer](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/b2d939/32.png) [@rwkreutzer](https://www.ruby-forum.com/u/rwkreutzer)\
**Post date:** [February 19, 2008, 5:01am UTC](https://www.ruby-forum.com/t/sum-the-product-of-two-fields/129505/3 "2008-02-19T05:01:09Z")

</div>

Hello,

have you tried it?

def total\_price  
@all\_items = LineItems.find :all  
@all\_items.inject(0) { |sum, li| sum + (li.quantity \*  
li.item\_price}  
end

I not check my script above, i hope you can inform me if found any  
error.

_~_~_~_~_~\*\*~_~_~_~_~_  
Reinhart Ariando  
YM : Booking2Heaven  
WEB : [http://teapoci.blogspot.com](http://teapoci.blogspot.com)

---

<div class="post-metadata">

**Author:** ![rwkreutzer](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/b2d939/32.png) [@rwkreutzer](https://www.ruby-forum.com/u/rwkreutzer)\
**Post date:** [February 19, 2008, 4:50pm UTC](https://www.ruby-forum.com/t/sum-the-product-of-two-fields/129505/4 "2008-02-19T16:50:12Z")

</div>

@Dick,

In your first attempt I believe the problem is that you’re working  
against the association proxy. It looks a lot like an array, but it’s  
not. When you ask it to ‘sum’, it’s actually trying to trigger a sum  
in the DB, rather than iterating through the line items.

In the subsequent attempts, the problem is one of scope. tpsum is  
local to the block that you’re using. When you attempt to return it,  
however, you’re outside the block and in a context that knows nothing  
about tpsum. You could fix any of those solutions by simply  
initializing tpsum=0 before the block.

s.ross, though, posts the more elegant solution.

On Feb 18, 10:34 pm, Dick K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![rwkreutzer](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/b2d939/32.png) [@rwkreutzer](https://www.ruby-forum.com/u/rwkreutzer)\
**Post date:** [February 20, 2008, 3:33am UTC](https://www.ruby-forum.com/t/sum-the-product-of-two-fields/129505/5 "2008-02-20T03:33:40Z")

</div>

On Feb 19, 2008, at 6:22 PM, Dick K. wrote:

> @Reinhart - works as implemented above, thanks.
> 
> @AndyV - thanks for the explanation. Local to the block, huh? I’m  
> not  
> used to that. I better skip ahead to the “introduction to ruby”  
> section  
> of my book. Thanks again.

I think you hit on it when you used 0 as the initializer for inject.  
By default, inject is supposed to used the first element of the  
enumerable as the starting value of the accumulator. That gives you a  
starting “a” of type LineItem, which is clearly not the intended type.  
By explicitly initializing it with a Fixnum, 0, you have created an  
accumulator (or memo) with a compliant type.

So the corrected code:

self.line\_items.inject(0) {|a, li| a += li.quantity \* li.item\_price }

should work without the parentheses around the product.

The inject method is quite idiomatic and if you look at some of the  
inject/reject/select/map/zip methods, it will remind you of Python or  
perhaps of certain aspects of functional programming. If you’re not  
into that, inject is not a really obvious choice.

–steve

---

<div class="post-metadata">

**Author:** ![rwkreutzer](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/b2d939/32.png) [@rwkreutzer](https://www.ruby-forum.com/u/rwkreutzer)\
**Post date:** [February 20, 2008, 8:17pm UTC](https://www.ruby-forum.com/t/sum-the-product-of-two-fields/129505/6 "2008-02-20T20:17:59Z")

</div>

Technically, it’s local to the scope in which it was created, and the  
block has it’s own scope that’s ‘nested’ within the scope of the  
total\_price method. So… you could declare it in total\_price and the  
block would see it, but not the other way around.

On Feb 19, 9:22 pm, Dick K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![rwkreutzer](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/b2d939/32.png) [@rwkreutzer](https://www.ruby-forum.com/u/rwkreutzer)\
**Post date:** [February 20, 2008, 3:22am UTC](https://www.ruby-forum.com/t/sum-the-product-of-two-fields/129505/7 "2008-02-20T03:22:32Z")

</div>

def total\_price  
#self.line\_items.inject{|a, li| a += li.quantity \* li.item\_price}  
@all\_items = self.line\_items.find :all  
@all\_items.inject(0) { |sum, li| sum + (li.quantity \*  
li.item\_price)}  
end

@Steve - I get the following error when I use the one-liner that’s  
commented out above.

undefined method `+’ for #LineItem:0x4654ccc

When I change it to

self.line\_items.inject(0) {|a, li| a += (li.quantity \* li.item\_price)}

It works fine. I plan to do some reading on inject (first time I’ve  
heard of it - kind of a noob), but if you’ve got any pointers I’d love  
the head start.

@Reinhart - works as implemented above, thanks.

@AndyV - thanks for the explanation. Local to the block, huh? I’m not  
used to that. I better skip ahead to the “introduction to ruby” section  
of my book. Thanks again.

---

<div class="post-metadata">

**Author:** ![rwkreutzer](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/b2d939/32.png) [@rwkreutzer](https://www.ruby-forum.com/u/rwkreutzer)\
**Post date:** [February 21, 2008, 1:58am UTC](https://www.ruby-forum.com/t/sum-the-product-of-two-fields/129505/8 "2008-02-21T01:58:07Z")

</div>

@Steve, @Andy - thanks for the help. You guys are great.
