frshca
frshca

Reputation: 1339

Merging many arrays into one array (JavaScript)

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

Answers (2)

I Hate Lazy
I Hate Lazy

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

jbabey
jbabey

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);
        }
    }
}

http://jsfiddle.net/Qhxzz/2/

Upvotes: 2

Related Questions