I have an array of items like so:
@items = [
{price: 12, quantity:1},
{price: 4, quantity:1},
{price: 8, quantity:1}
]
And I am looking for something like this:
sumPrice: ->
@items.sum (item) -> item.price * item.quantity
Or anything as close as possible to this, that makes it super-easy for everyone reading the code to understand whats happening.
So far I came up with:
sumPrice: ->
(items.map (a) -> a.price * a.quantity).reduce (a, b) -> a + b
And:
sumPrice: ->
sum = 0
for item in items
sum += item.price * item.quantity
sum
I love CoffeeScript so I hope there is a nicer solution to this & similar scenarios that I miss.
Functional style is not so bad. CoffeeScript allows you to prettify your code like this:
items
.map (item) ->
item.price * item.quantity
.reduce (x,y) ->
x+y
This code is easier for understanding than your one-liner.
If you don't like map
you can use for
instead. Like this:
(for item in items
item.price * item.quantity)
.reduce (x,y)->x+y
Or like this:
prods = for item in items
item.price * item.quantity
prods.reduce (x,y)->x+y
Or you can add your own sum()
method for arrays:
Array::sum = -> @reduce (x,y)->x+y
(item.price * item.quantity for item in items).sum()
If you want to express the solution as @items.sum (item) -> item.price * item.quantity
you can add a sum
method to Array
:
Array::sum = (fn = (x) -> x) ->
@reduce ((a, b) -> a + fn b), 0
sum = @items.sum (item) -> item.price * item.quantity
Notice that i'm passing 0
as the initial value of reduce
so the fn
callback is called for every array value.
If you don't like extending the builtin objects, i guess you could express the sum as a single reduce elegantly if you extract the logic of calculating the total price for a single array item in its own function:
itemPrice = (item) -> item.price * item.quantity
sum = items.reduce ((total, item) -> total + itemPrice item), 0
You can use destructuring to simplify the code slightly:
sumPrice: ->
sum = 0
sum += price * quantity for {price, quantity} in @items
sum
I don't think there's any way to get rid of the explicit initialization of sum
. While Coffeescript's for
loop syntax tends to help simplify code that would otherwise use map()
, it doesn't really have anything analogous that simplifies reduce()
-type operations, which is what sumPrice
is doing here.
As mentioned in the comments, one advantage this solution has over a call to reduce()
or sum()
is that it avoids the overhead of creating and repeatedly calling a function.
sum = 0
value = (item) ->
item.price * item.quantity
sum += value(item) for item in @items
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With