最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - lodash sum of array of objects - Stack Overflow

programmeradmin1浏览0评论

I just started learning about lodash, and trying to incorporate it in my code. As you can see I am adding the weights of each of the elements under employee. The issue is I am having is I am not sure how to get the third element "gender" into my final array of data. I used this Reduce array of objects on key and sum value into array to construct my lodash code. You can see below on how am trying to get my output.

var userAns = [{
    id: 1,
    text: "answer1",
    employee: [{
        name: "John",
        weight: 3,
        gender: "male"
      },
      {
        name: "Sally",
        weight: 4,
        gender: "female"
      }
    ]
  },
  {
    id: 2,
    text: "answer2",
    employee: [{
        name: "John",
        weight: 6,
        gender: "male"
      },
      {
        name: "Sally",
        weight: 3,
        gender: "female"
      }
    ]
  }
];

var scores = [];
for (var i = 0; i < userAns.length; i++) {
  for (var j = 0; j < userAns[i].employee.length; j++) {
    scores.push(userAns[i].employee[j]);
  }
}

var result = _(scores)
  .map('name')
  .uniq()
  .map(function(key) {

    return {
      name: key,
      score: _(scores).filter({
        name: key
      }).sumBy('weight')
    };
  })
  .value();

console.log(result);
<script src=".14.1/lodash.min.js"></script>

I just started learning about lodash, and trying to incorporate it in my code. As you can see I am adding the weights of each of the elements under employee. The issue is I am having is I am not sure how to get the third element "gender" into my final array of data. I used this Reduce array of objects on key and sum value into array to construct my lodash code. You can see below on how am trying to get my output.

var userAns = [{
    id: 1,
    text: "answer1",
    employee: [{
        name: "John",
        weight: 3,
        gender: "male"
      },
      {
        name: "Sally",
        weight: 4,
        gender: "female"
      }
    ]
  },
  {
    id: 2,
    text: "answer2",
    employee: [{
        name: "John",
        weight: 6,
        gender: "male"
      },
      {
        name: "Sally",
        weight: 3,
        gender: "female"
      }
    ]
  }
];

var scores = [];
for (var i = 0; i < userAns.length; i++) {
  for (var j = 0; j < userAns[i].employee.length; j++) {
    scores.push(userAns[i].employee[j]);
  }
}

var result = _(scores)
  .map('name')
  .uniq()
  .map(function(key) {

    return {
      name: key,
      score: _(scores).filter({
        name: key
      }).sumBy('weight')
    };
  })
  .value();

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

Here is how I am trying to get my array

[
  {
    "name": "John",
    "score": 9,
    "gender": "male"
  },
  {
    "name": "Sally",
    "score": 7,
    "gender":"female" 
  }
]

Share Improve this question edited Dec 2, 2017 at 5:56 user990951 asked Dec 2, 2017 at 5:40 user990951user990951 1,4795 gold badges26 silver badges36 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 1

Using lodash:

You can use a bination of _.flatMap(), _.groupBy(), _.map() and _.mergeWith():

var userAns = [{"id":1,"text":"answer1","employee":[{"name":"John","weight":3,"gender":"male"},{"name":"Sally","weight":4,"gender":"female"}]},{"id":2,"text":"answer2","employee":[{"name":"John","weight":6,"gender":"male"},{"name":"Sally","weight":3,"gender":"female"}]}];

var result = _(userAns)
  .flatMap('employee') // create an array of all emplyoees
  .groupBy('name') // create groups of employees with the same name
  .map(function(g) {
    // merge each group to a single object, and bine weight values
    return _.mergeWith.apply(_, [{}].concat(g, function(obj, src, key) {
      return key === 'weight' ? (obj || 0) + src : undefined;
    }));
  })
  .value();
  
console.log(result);
<script src="https://cdnjs.cloudflare./ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Using ES6:

Use Array#map to get an array of employee arrays, and flatten by spreading into Array#concat. Reduce the array into a Map, then convert back to an array by spreading the Map#values iterator:

const userAns = [{"id":1,"text":"answer1","employee":[{"name":"John","weight":3,"gender":"male"},{"name":"Sally","weight":4,"gender":"female"}]},{"id":2,"text":"answer2","employee":[{"name":"John","weight":6,"gender":"male"},{"name":"Sally","weight":3,"gender":"female"}]}];

const result = [...
  [].concat(...userAns.map(({ employee }) => employee)) // bine all employees to a single array
  .reduce((m, o) => { // reduce similar employees to a single object in a Map, and bine weight
    // if the name object doesn't exists create a new one by cloning the object, and assigning weight: 0
    m.has(o.name) || m.set(o.name, Object.assign({}, o, { weight: 0 }));
    
    m.get(o.name).weight += o.weight; // add the current weight to the name object
    
    return m;
  }, new Map())
  .values()]; // get the Map values, and spread to convert to array
  
console.log(result);

You can make use of lodash find method and then pluck the key which you want from the Object and get the value of the Object using values and assign it to gender key of the final resultant Object

var userAns = [{
    id: 1,
    text: "answer1",
    employee: [{
        name: "John",
        weight: 3,
        gender: "male"
      },
      {
        name: "Sally",
        weight: 4,
        gender: "female"
      }
    ]
  },
  {
    id: 2,
    text: "answer2",
    employee: [{
        name: "John",
        weight: 6,
        gender: "male"
      },
      {
        name: "Sally",
        weight: 3,
        gender: "female"
      }
    ]
  }
];

var scores = [];
for (var i = 0; i < userAns.length; i++) {
  for (var j = 0; j < userAns[i].employee.length; j++) {
    scores.push(userAns[i].employee[j]);
  }
}

var result = _(scores)
  .map('name')
  .uniq()
  .map(function(key) {
    return {
      name: key,
      gender: _.values(_.pick(_.find(scores, (d) => d.name == key),'gender'))[0],
      score: _(scores).filter({
        name: key
      }).sumBy('weight')
    };
  })
  .value();

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

You can acplish this without lodash. You can use array#reduce to first accumulate all your employee array inside each userAns and then again using array#reduce you can sum up the weight. Then, get the output using Object.values()

var userAns = [{ id: 1, text: "answer1", employee: [{ name: "John", weight: 3, gender: "male" }, { name: "Sally", weight: 4, gender: "female" } ] }, { id: 2, text: "answer2", employee: [{ name: "John", weight: 6, gender: "male" }, { name: "Sally", weight:3, gender: "female" }]}];

var result = userAns
              .reduce((r,o) => r.concat(o.employee),[])
              .reduce((r,o) => {
                  if(r[o.name])
                      r[o.name].weight += o.weight;
                  else
                    r[o.name] = o;
                  return r;
              },{});
              
var output = Object.values(result);
console.log(output);

You can do this by doing minor modification. First get your user inside map like below

var user = _(scores).filter({
  name: key
});

Then, you can extract score's sum and gender from it as following

return {
  name: key,
  score: user.sumBy('weight'),
  gender: user.get('[0]').gender
};

Please find modified snippet below

var userAns = [{
  id: 1,
  text: "answer1",
  employee: [{
    name: "John",
    weight: 3,
    gender: "male"
  }, {
    name: "Sally",
    weight: 4,
    gender: "female"
  }]
}, {
  id: 2,
  text: "answer2",
  employee: [{
    name: "John",
    weight: 6,
    gender: "male"
  }, {
    name: "Sally",
    weight: 3,
    gender: "female"
  }]
}];

var scores = [];
for (var i = 0; i < userAns.length; i++) {
  for (var j = 0; j < userAns[i].employee.length; j++) {
    scores.push(userAns[i].employee[j]);
  }
}


var result = _(scores)
  .map('name')
  .uniq()
  .map(function(key) {
    var user = _(scores).filter({
      name: key
    });
    return {
      name: key,
      score: user.sumBy('weight'),
      gender: user.get('[0]').gender
    };
  })
  .value();

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

发布评论

评论列表(0)

  1. 暂无评论