I am trying to understand how reduce works
var expense = [
{
item: "Bed",
cost: 1499,
date: "02-23-2018"
},
{
item: "Phone",
cost: 2499,
date: "02-23-2018"
},
{
item: "Book",
cost: 400,
date: "02-23-2018"
},
{
item: "Mattress",
cost: 700,
date: "02-23-2018"
},
{
item: "Food",
cost: 300,
date: "02-23-2018"
}
];
var totalExpense = expense.reduce(function (a, b) {
console.log(a.cost, b.cost);
return a.cost + b.cost;
});
console.log(totalExpense);
this gives totalExpense as NaN
.
Output:
1499 2499
undefined 400
undefined 700
undefined 300
NaN
When I perform the same operation with a simple expense array, it works fine.
I am trying to understand how reduce works
var expense = [
{
item: "Bed",
cost: 1499,
date: "02-23-2018"
},
{
item: "Phone",
cost: 2499,
date: "02-23-2018"
},
{
item: "Book",
cost: 400,
date: "02-23-2018"
},
{
item: "Mattress",
cost: 700,
date: "02-23-2018"
},
{
item: "Food",
cost: 300,
date: "02-23-2018"
}
];
var totalExpense = expense.reduce(function (a, b) {
console.log(a.cost, b.cost);
return a.cost + b.cost;
});
console.log(totalExpense);
this gives totalExpense as NaN
.
Output:
1499 2499
undefined 400
undefined 700
undefined 300
NaN
When I perform the same operation with a simple expense array, it works fine.
Share Improve this question edited Sep 27, 2021 at 5:46 Jun Yu 4241 gold badge8 silver badges22 bronze badges asked Jan 28, 2018 at 18:53 Stacy JStacy J 2,78116 gold badges59 silver badges93 bronze badges7 Answers
Reset to default 20The first parameter you pass to reduce's callback is the previous value (a
) - or the second argument you pass to reduce (the initial value)
[].reduce(function(a, b) { ... }, 0);
^ callback ^ initial value
a
will hold the result of each previous iteration, So to get the total of all costs, simply add b.cost
var expense = [{
item: 'Bed',
cost: 1499,
date: '02-23-2018'
},
{
item: 'Phone',
cost: 2499,
date: '02-23-2018'
},
{
item: 'Book',
cost: 400,
date: '02-23-2018'
},
{
item: 'Mattress',
cost: 700,
date: '02-23-2018'
},
{
item: 'Food',
cost: 300,
date: '02-23-2018'
}
];
var totalExpense = expense.reduce(function(a, b) {
return a + b.cost;
}, 0);
console.log(totalExpense);
Using es6 syntax you could make it a one liner
var totalExpense = expense.reduce((a, {cost}) => a + cost, 0);
You need to provide an initial value which has a cost
field in order to reference it in the accumulator. And you need to return that object:
expense.reduce(function(acc, curr){
console.log(acc.cost, curr.cost);
acc.cost += curr.cost;
return acc;
}, { cost: 0 });
Note the use of more meaningful variable names than a
and b
. This will make your code easier to understand. The Array.prototype.reduce
callback should have an accumulator and current value. Name them as such to help yourself. The initial value provides an object with a cost
field where you can write down your accumulated value.
Note that you could also just use a vanilla variable here if you wanted to. If you don't actually need an object:
var total = expense.reduce(function(acc, curr){
acc += curr.cost;
return acc;
}, 0);
console.log(total);
>> 5398
You need to return
whatever the next a
should be. a.cost + b.cost
is a number. It doesn’t have a cost
property, so a.cost
will be undefined
after the first iteration.
Just provide a starting value 0
. Also consider giving your parameters more appropriate names.
var totalExpense = expense.reduce(function(sum, item){
return sum + item.cost;
}, 0);
You need an initial value. The reduce function takes the accumulated value as first parameter and the next element of the collection as second
var totalExpense = expense.reduce(function(accumulator, current) {
console.log({ accumulator: accumulator, currentCost: current.cost });
return accumulator + current.cost;
}, 0);
console.log({ totalExpense: totalExpense });
//total cost by reduce method
let totalExpense = expense.reduce((tem,val) => tem+=val.cost,0) console.log(totalExpense)
expense.reduce((sum, cur) => ({ cost: sum.cost + cur.cost })).cost;
Updated As @Viktor pointed, I didn't consider special case before.
function getTotelExpense(expense) {
if (expense.length > 0 && expense[0].hasOwnProperty("cost"))
return expense.reduce((sum, cur) => ({ cost: sum.cost + cur.cost })).cost;
else return 0;
}
You can learn more in TypeError: Reduce of empty array with no initial value | MDN
Here's another way you can do it using the generic function foldMap
– for more guidance on this beautiful function, I recommend this video.
const totalExpense =
expense.foldMap (item => item.cost, 0)
console.log (totalExpense)
// 5398
For this, you'll need to define Array.prototype.foldMap
and Number.prototype.concat
– but this implementation and where it is defined is up to you
Array.prototype.foldMap = function (f, acc)
{
return this.reduce ((acc, x, i) =>
acc.concat (f (x, i, this)), acc)
}
Number.prototype.concat = function (m)
{
return this + m
}
Here's a functioning code paste
Array.prototype.foldMap = function (f, acc)
{
return this.reduce ((acc, x, i) =>
acc.concat (f (x, i, this)), acc)
}
Number.prototype.concat = function (m)
{
return this + m
}
const expense =
[ { item: 'Bed'
, cost: 1499
, date: '02-23-2018'
}
, { item: 'Phone'
, cost: 2499
, date: '02-23-2018'
}
, { item: 'Book'
, cost: 400
, date: '02-23-2018'
}
, { item: 'Mattress'
, cost: 700
, date: '02-23-2018'
}
, { item: 'Food'
, cost: 300
, date: '02-23-2018'
}
]
const totalExpense =
expense.foldMap (item => item.cost, 0)
console.log(totalExpense)
// 5398