13

I have been trying to get this right and was having issues so figured i should ask ppl with more experience. I have an array of objects lets say called items, and I need to sum up some of the properties across different objects in the array and sum them up those at the end. The user can make a few selections and i need to only sum up the only the chosen properties in the array they give me so i thought maybe to use the _.pick function in lodash. If possible i would like to do that in one loop since the items array could have upto a 1000 items. Here is an example:

var items = [
{'lightBlue':4, 'darkBlue':2, 'red':4, 'orange':6, 'purple':7},
{'lightBlue':6, 'darkBlue':5, 'red':1, 'orange':2, 'purple':3},
{'lightBlue':2, 'darkBlue':4, 'red':3, 'orange':4, 'purple':9}
]

var userSelectedColors = ['lightBlue', 'darkBlue'];

What I want to see is all the blue's summed up like:

var summedUp = [{'lightBlue':12, 'darkBlue':11}];

Then sum up the results to get the total no

var totalCount = 23

Whats the best and performant way to get this in lodash. The array of userSelectedColors could be 1 or any combination of the colors.

Please provide an example, thanks your helps appreciated!

2
  • Unless items is very very large, performance likely won't be a concern. A non-lodash solution would probably be fastest. Commented Jul 19, 2016 at 2:43
  • Hi thanks @4castle can you provide an example of how to get the result i mentioned above? Commented Jul 19, 2016 at 2:45

3 Answers 3

23

Use _.sumBy

var totalCount = _.sumBy(userSelectedColors, _.partial(_.sumBy, items));

var items = [
  { 'lightBlue': 4, 'darkBlue': 2, 'red': 4, 'orange': 6, 'purple': 7 },
  { 'lightBlue': 6, 'darkBlue': 5, 'red': 1, 'orange': 2, 'purple': 3 },
  { 'lightBlue': 2, 'darkBlue': 4, 'red': 3, 'orange': 4, 'purple': 9 }
], userSelectedColors = ['lightBlue', 'darkBlue'];

var totalCount = _.sumBy(userSelectedColors, _.partial(_.sumBy, items));

console.log(totalCount);
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>

Expanded, that looks like:

var totalCount = _.sumBy(userSelectedColors, function(prop) {
    return _.sumBy(items, prop);
});

Without Lodash, a more performant solution would be something like this:

var totalCount = items.reduce(function(total, obj) {
    return total + userSelectedColors.reduce(function(total, prop) {
        return total + obj[prop];
    }, 0);
}, 0);

var items = [
  { 'lightBlue': 4, 'darkBlue': 2, 'red': 4, 'orange': 6, 'purple': 7 },
  { 'lightBlue': 6, 'darkBlue': 5, 'red': 1, 'orange': 2, 'purple': 3 },
  { 'lightBlue': 2, 'darkBlue': 4, 'red': 3, 'orange': 4, 'purple': 9 }
], userSelectedColors = ['lightBlue', 'darkBlue'];

var totalCount = items.reduce(function(total, obj) {
    return total + userSelectedColors.reduce(function(total, prop) {
        return total + obj[prop];
    }, 0);
}, 0);

console.log(totalCount);
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>

Sign up to request clarification or add additional context in comments.

10 Comments

Actually, this doesn't give you access to the summary ({ lightBlue: 12, darkBlue: 13 }). Maybe I misunderstood the question?
@smarx Hmm, well the OP selected it, maybe they only really cared about the totalCount?
@4castle I guess so. I've deleted my answer, but I can resurrect it if it turns out the summary is needed. :-)
Yes @smarx i was just trying to explain the process ultimately i wanted the aggregate sum.
@jamesemanon Sure. It's a functional programming technique I learned from Haskell. It's just a short way of saying to apply the first parameter of the callback to the second parameter of the nested _.sumBy. I've editted to show more of that.
|
5

In terms of efficiency, I believe this is hard to beat, since it only iterates once through the array, but it's not quite as succinct as an approach like the one @4castle took. (Also, for only 1000 items, you're never going to notice the performance difference anyway.)

var items = [
    {'lightBlue':4, 'darkBlue':2, 'red':4, 'orange':6, 'purple':7},
    {'lightBlue':6, 'darkBlue':5, 'red':1, 'orange':2, 'purple':3},
    {'lightBlue':2, 'darkBlue':4, 'red':3, 'orange':4, 'purple':9}
]

var userSelectedColors = ['lightBlue', 'darkBlue'];

var sums = {};

_.each(items, function (item) {
    _.each(userSelectedColors, function (color) {
        sums[color] = (sums[color] || 0) + item[color];
    });
});

console.log('Summary: ', sums);

console.log('Grand total: ', _.sum(_.values(sums)));

Output:

Summary:  { lightBlue: 12, darkBlue: 11 }
Grand total:  23

1 Comment

Awesome, thank you! I was looking for something without nested loops, (I have something similar, just using lodash forEach). Anyway thank you so much for helping me out!
1

Getting the Summary

var summary = userSelectedColors.map(c => ({ [c]: _.sumBy(items, c)}))

Total

var total = _.sum(Object.values(summary))

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.