Reputation: 3
I have an array of objects where each index is one week where I bought groceries. Meaning that array[0] is the first week, array[1] is the second and the so on. What I need to do is do sum all the values of the same items using Underscore (not for loop, or while). Here is one example:
console.log(weeklyGroceries([
{
apple: 1,
banana: 4,
fish: 2,
melon: 3,
},
{
apple: 3,
banana: 2,
fish: 5,
melon: 1,
}
]));
It should print:
{
apple: 4,
banana: 6,
fish: 27,
melon: 4
}
Any ideas?
I have tried using reduce to get all the values, but I still have to sum the same values it wouldn't be in object form anymore.
var keys = array.reduce((value,obj) => [...value, ...Object.values(obj)],[]);
Upvotes: 0
Views: 187
Reputation: 4366
Here is a fun exercise in functional programming. Assuming you already have a sum
function for simple arrays of numbers, you can implement weeklyGroceries
in just two expressions. No loops, anonymous functions or if
/else
required:
var add = (a, b) => a + b;
var sum = _.partial(_.reduce, _, add, 0);
function weeklyGroceries(groceriesByDay) {
var keys = _.chain(groceriesByDay)
.map(_.keys).flatten().uniq().value();
return _.chain(keys).zip(keys).object()
.mapObject(_.property)
.mapObject(_.partial(_.map, groceriesByDay))
.mapObject(_.compose(sum, _.compact))
.value();
}
console.log(weeklyGroceries([{
apple: 1,
banana: 4,
fish: 2,
melon: 3,
}, {
apple: 3,
banana: 2,
fish: 5,
melon: 1,
}]));
<script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script>
While the implementation of weeklyGroceries
is not straightforward, figuring out how it works will deepen your understanding of functional programming. This will empower you to write some things very concisely, such as the definition of sum
at the top.
For the convenience of the reader, here are links to the documentation of each Underscore function used in this snippet, by order of evaluation:
_.partial
_.reduce
_.chain
_.map
_.keys
_.flatten
_.uniq
_.value
_.zip
_.object
_.mapObject
_.property
_.partial
_.compose
_.compact
Upvotes: 1
Reputation: 1259
Try this, pure js:
function weeklyGroceries(arr) {
return arr.reduce((acc, curr) => {
for (const key in curr) {
if(acc[key]) {
acc[key] = acc[key] + curr[key];
} else {
acc[key] = curr[key];
}
}
return acc;
}, {});
}
Upvotes: 0
Reputation: 3436
Using reduce
is the very good idea. I guess you were misleaded a bit by reduce
signature Consider following:
reduce((accumulator, currentValue) => { /* … */ })
It means, that reduce will work on each iteration with some kind of accumulator
(this will carry on sum on each loop iteration) and current value of array, one after another on each iteration.
weeklyGroceries.reduce((acc, currentValue) => {
return {
apple: acc.apple + currentValue.apple,
banana: acc.banana + currentValue.banana,
fish: acc.fish + currentValue.fish,
melon: acc.melon + currentValue.melon,
}
}, {
apple: 0,
banana: 0,
fish: 0,
melon: 0,
})
If, for some reason, like training or just for fun, you wish to avoid using build-in functions, you can achieve same, by manually iterating over every entry of your object and sum all respective fields:
let sums = {};
Object.keys(weeklyGroceries[0]).forEach(key => {
console.log(key)
let partailSum = 0;
for (let idx = 0; idx < weeklyGroceries.length; idx++) {
partailSum += weeklyGroceries[idx][key];
}
sums[key] = partailSum;
})
Upvotes: 1
Reputation: 612
You can use the _.reduce
function from the Underscore library to sum the values of the same items in the array of objects.
Here is an example:
function weeklyGroceries(weeks) {
return _.reduce(weeks, function(result, week) {
_.each(week, function(value, key) {
result[key] = (result[key] || 0) + value;
});
return result;
}, {});
}
Upvotes: 2