Reputation: 1479
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.net/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"
}
]
Upvotes: 0
Views: 9695
Reputation: 191936
Using lodash:
You can use a combination 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 combine 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.com/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)) // combine all employees to a single array
.reduce((m, o) => { // reduce similar employees to a single object in a Map, and combine 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);
Upvotes: 1
Reputation: 6546
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.net/lodash/4.14.1/lodash.min.js"></script>
Upvotes: 0
Reputation: 22524
You can accomplish 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);
Upvotes: 1
Reputation: 19622
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.net/lodash/4.14.1/lodash.min.js"></script>
Upvotes: 1