Sum values in a Array of JavaScript deep Objects

I have been searching for a solution and trying different things to get the solutions i am looking for for hours. I have an array below I want to be able to do two things to the array separately. (so two separate functions)

Function 1. I want to to sum all the "weight" values. (i.e 3 + 2 + 1 + 2 + 1 + 1 + 0) I have tried using lodash sumBy which does a fine job in summing the simple objects in the array.

Function 2. I want to be able to iterate through the elements ( I have been trying to flatten the object using lodash but with no luck.)

I am looking for any help. I apologize if the is a newbie question or if its something already solved, for some reason I can't find the right search terms.

EDIT: Currently using es5, so arrow functions are not available

var answers = [{
    '1': {
      id: '5aa2542e4e31482f1e',
      text: 'Employee',
      orderNo: 2,
      weight: 3,
    },
    '5': {
      id: '5a442e47339482f22',
      text: 'Worker',
      orderNo: 6,
      weight: 2,
    }
  },
  {
    '2': {
      id: '5a52442e4739482f51',
      text: 'Time Sensive',
      orderNo: 3,
      weight: 1,
    },
    '3': {
      id: '5a2442e47e3932f52',
      text: 'Group Sensitive',
      orderNo: 4,
      weight: 2,
    }
  },
  {
    id: '5a57d9375a5a7ac20317',
    text: 'Med',
    orderNo: 1,
    weight: 1
  },
  {
    id: '5a57da0755a7ac4691c',
    text: 'Med ',
    orderNo: 2,
    weight: 1
  },
  {
    id: '5a57da545aa7ac206220',
    text: 'Yes',
    orderNo: 1,
    weight: 0
  }
]
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

3 answers

  • answered 2018-01-12 15:10 Epitouille

    The basic solution is to flatten your array

    const x = answers.map(obj => Object.values(obj))
    

    After that you have a array of array

    You can join these array using reduce.

    const flattenedAnswers = x.reduce((acc, item) => acc.concat(item), []);
    

    to sum the weight, you can use map and reduce

    const sum = flattenedAnswers.map(item => item.weigt).reduce((acc, item) => acc + item), 0);
    

    To iterate over the items, just iterate over the flattened answers array

    var answers = [{
        '1': {
          id: '5aa2542e4e31482f1e',
          text: 'Employee',
          orderNo: 2,
          weight: 3,
        },
        '5': {
          id: '5a442e47339482f22',
          text: 'Worker',
          orderNo: 6,
          weight: 2,
        }
      },
      {
        '2': {
          id: '5a52442e4739482f51',
          text: 'Time Sensive',
          orderNo: 3,
          weight: 1,
        },
        '3': {
          id: '5a2442e47e3932f52',
          text: 'Group Sensitive',
          orderNo: 4,
          weight: 2
        }
      }
    ]
    
    const flat = answers.map(x => Object.values(x)).reduce((acc, item) => acc.concat(item), []);
    
    const sum = flat.map(x => x.weight).reduce((acc, item) => acc + item, 0);
    
    console.log(sum)

  • answered 2018-01-12 15:10 TKoL

    You can iterate the array elements by answers.forEach(answer => {...})

    You can iterate the answer properties by Object.keys(answer).forEach(key => {let val = answer[key]})

    Look for the Weight property in each answer and in each val, and if it's there, add it to a variable you've defined outside of the foreach functions.

  • answered 2018-01-12 15:10 Gruff Bunny

    The first thing to do is to sanitize that array into an array of answers:

    var allAnswers = _.flatMap(answers, function(answer){
        return _.has(answer, 'id') ? answer : _.values(answer)
    });
    

    From then on it's easy to calculate the sum of the weights:

    var totalWeight = _.sumBy(allAnswers, 'weight');
    

    And to iterate:

    allAnswers.forEach(allAnswers, function(answer) {
        // do whatever I need to with the answer
    });