Reputation: 1339
I'm trying to take an array of many arrays that contain many objects and manipulate it into an array of objects.
So, let's say I have an array that looks like this:
[
[
{Name: 'Josh', email: '[email protected]', Points: 33},
{Name: 'Doug', email: '[email protected]', Points: 12}
],
[
{Name: 'Josh', email: '[email protected]', Points: 11},
{Name: 'Doug', email: '[email protected]', Points: 18}
],
[
{Name: 'Josh', email: '[email protected]', Points: 2},
{Name: 'Doug', email: '[email protected]', Points: 27}
]
]
The Desired outcome would be an array of objects that has a 'Points' property to hold an array of the points. So it would look like this:
[
{Name: 'Josh', email: '[email protected]', Points: [33, 11, 2]},
{Name: 'Doug', email: '[email protected]', Points: [12, 18, 27]}
]
This problem seems simple, but I can't seem to figure out the best way of doing this. If you want this data in a fiddle, I made this for you to play with: http://jsfiddle.net/Qhxzz/1/
Upvotes: 1
Views: 153
Reputation: 48819
Here's one way using .reduce()
and .forEach()
. (You'll need patches if you're supporting older browsers.)
var consolidated = data.reduce(function(holder, arr) {
arr.forEach(function(obj) {
if (obj.email in holder.emails)
holder.emails[obj.email].Points.push(obj.Points);
else {
holder.emails[obj.email] = obj;
holder.result.push(obj);
obj.Points = [obj.Points];
}
});
return holder;
}, {emails:{},result:[]}).result;
And actually, we could flatten out the original Array using concat.apply()
, and be left with one monolithic Array to iterate.
flat = [].concat.apply([], data);
This turns your data
into this structure:
[{Name:"Josh", email:"[email protected]", Points:33},
{Name:"Doug", email:"[email protected]", Points:12},
{Name:"Josh", email:"[email protected]", Points:11},
{Name:"Doug", email:"[email protected]", Points:18},
{Name:"Josh", email:"[email protected]", Points:2},
{Name:"Doug", email:"[email protected]", Points:27}]
And makes the consolidation a bit simpler by eliminating the need for the inner .forEach()
.
var consolidated = flat.reduce(function(holder, obj) {
if (obj.email in holder.emails)
holder.emails[obj.email].Points.push(obj.Points);
else {
holder.emails[obj.email] = obj;
holder.result.push(obj);
obj.Points = [obj.Points];
}
return holder;
}, {emails:{}, result:[]}).result;
Upvotes: 2
Reputation: 46657
Note that this depends on the input structure being static (no recursion here). Assuming you're not using any libraries:
var result = [];
for (var i = 0; i < initial.length; i++) {
var innerArray = initial[i];
for (var j = 0; j < innerArray.length; j++) {
var item = innerArray[j];
var found = false;
// search result for an object with a matching email prop
for (var k = 0; k < result.length; k++) {
if (result[k].email === item.email) {
found = true;
// add this Point to the Points array
result[k].Points.push(item.Points);
}
}
if (!found) {
// convert Points to an array of Points
item.Points = [item.Points];
result.push(item);
}
}
}
Upvotes: 2