0

I'd like to sum objects from array, I've been searching and testing different things founds around there, using Lodash or not, without any success.

Here is the data array, there is 5 elements but it could be less or more. The properties will always be the same, but there could be a lot more.

const data = [
    {
        from: "2019-10-15",
        stats: [
            {
                options: {
                    width: 15,
                    height: 20,
                    borders: 35,
                    removable: 5
                }
            }
        ]
    },
    {
        from: "2019-10-16",
        stats: [
            {
                options: {
                    width: 22,
                    height: 18,
                    borders: 10,
                    removable: 0
                }
            }
        ]
    },
    {
        from: "2019-10-17",
        stats: [
            {
                options: {
                    width: 0,
                    height: 15,
                    borders: 15,
                    removable: 0
                }
            }
        ]
    },
    {
        from: "2019-10-18",
        stats: [
            {
                options: {
                    width: 20,
                    height: 20,
                    borders: 10,
                    removable: 5,
                }
            }
        ]
    },
    {
        from: "2019-10-19",
        stats: [
            {
                options: {
                    width: 0,
                    height: 10,
                    borders: 0,
                    removable: 30
                }
            }
        ]
    }
];

The expected result is the sum of each array element stats[0].options properties:

const sum = {
    width: 57,
    height: 83,
    borders: 70,
    removable: 40
}

I know it's definitely not complicated.

3 Answers 3

3

Use _.map() to get the options, then combine the objects using _.mergeWith(), and use _.add() as the customizer.

const data = [{"from":"2019-10-15","stats":[{"options":{"width":15,"height":20,"borders":35,"removable":5}}]},{"from":"2019-10-16","stats":[{"options":{"width":22,"height":18,"borders":10,"removable":0}}]},{"from":"2019-10-17","stats":[{"options":{"width":0,"height":15,"borders":15,"removable":0}}]},{"from":"2019-10-18","stats":[{"options":{"width":20,"height":20,"borders":10,"removable":5}}]},{"from":"2019-10-19","stats":[{"options":{"width":0,"height":10,"borders":0,"removable":30}}]}];

const result = _.mergeWith({}, ..._.map(data, 'stats[0].options'), _.add);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

If you use lodash/fp you can create a function using _.flow(), and replace _.mergeWith with _.mergeAllWith():

const { flow, map, mergeAllWith, add } = _;

const fn = flow(
  map('stats[0].options'),
  mergeAllWith(add)
);

const data = [{"from":"2019-10-15","stats":[{"options":{"width":15,"height":20,"borders":35,"removable":5}}]},{"from":"2019-10-16","stats":[{"options":{"width":22,"height":18,"borders":10,"removable":0}}]},{"from":"2019-10-17","stats":[{"options":{"width":0,"height":15,"borders":15,"removable":0}}]},{"from":"2019-10-18","stats":[{"options":{"width":20,"height":20,"borders":10,"removable":5}}]},{"from":"2019-10-19","stats":[{"options":{"width":0,"height":10,"borders":0,"removable":30}}]}];

const result = fn(data);

console.log(result);
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>

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

Comments

2

It can be done through vanill JavaScript. Just use reduce and foreach methods:

const data = [
    {
        from: "2019-10-15",
        stats: [
            {
                options: {
                    width: 15,
                    height: 20,
                    borders: 35,
                    removable: 5
                }
            }
        ]
    },
    {
        from: "2019-10-16",
        stats: [
            {
                options: {
                    width: 22,
                    height: 18,
                    borders: 10,
                    removable: 0
                }
            }
        ]
    },
    {
        from: "2019-10-17",
        stats: [
            {
                options: {
                    width: 0,
                    height: 15,
                    borders: 15,
                    removable: 0
                }
            }
        ]
    },
    {
        from: "2019-10-18",
        stats: [
            {
                options: {
                    width: 20,
                    height: 20,
                    borders: 10,
                    removable: 5,
                }
            }
        ]
    },
    {
        from: "2019-10-19",
        stats: [
            {
                options: {
                    width: 0,
                    height: 10,
                    borders: 0,
                    removable: 30
                }
            }
        ]
    }
];

const result = data.reduce((a, {stats}) => {
    stats.forEach(({options}) => {
        for (const key in options) {
            a[key] = a[key] || 0;
            a[key] += options[key];
        }
    });

    return a;
}, {})

console.log(result);

The vanilla JS code looks like this:

const result = data.reduce((a, {stats}) => {
    stats.forEach(({options}) => {
        for (const key in options) {
            a[key] = a[key] || 0;
            a[key] += options[key];
        }
    });

    return a;
}, {})

Comments

0

Another approach to do this with a reduce and nested forEach, but a bit more straightforward:

const data = [
    {
        from: "2019-10-15",
        stats: [
            {
                options: {
                    width: 15,
                    height: 20,
                    borders: 35,
                    removable: 5
                }
            }
        ]
    },
    {
        from: "2019-10-16",
        stats: [
            {
                options: {
                    width: 22,
                    height: 18,
                    borders: 10,
                    removable: 0
                }
            }
        ]
    },
    {
        from: "2019-10-17",
        stats: [
            {
                options: {
                    width: 0,
                    height: 15,
                    borders: 15,
                    removable: 0
                }
            }
        ]
    },
    {
        from: "2019-10-18",
        stats: [
            {
                options: {
                    width: 20,
                    height: 20,
                    borders: 10,
                    removable: 5,
                }
            }
        ]
    },
    {
        from: "2019-10-19",
        stats: [
            {
                options: {
                    width: 0,
                    height: 10,
                    borders: 0,
                    removable: 30
                }
            }
        ]
    }
];

let result = _.reduce(data, (acc, value) =>{
      // our nested options object
      const options = value.stats[0].options;
      
      _.forEach(options, (optionValue, optionKey) =>{
        // if we know about this key already, then add optionValue to it
        // if not, this will be our first value for that key
        acc[optionKey] = !!acc[optionKey] ? acc[optionKey] + optionValue : optionValue;
      })
      
      return acc;
}, {})

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

Comments

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.