plus-
plus-

Reputation: 46543

In Javascript, how to merge array of objects?

var array1 = [{ "name" : "foo" , "age" : "22"}, { "name" : "bar" , "age" : "33"}];
var array2 = [{ "name" : "foo" , "age" : "22"}, { "name" : "buz" , "age" : "35"}];

What's the fastest way to have (no duplicates, name is the identifier):

[{ "name" : "foo" , "age" : "22"}, { "name" : "bar" , "age" : "33"}, { "name" : "buz" , "age" : "35"}];

With and without jquery if possible.

Upvotes: 1

Views: 715

Answers (4)

jfriend00
jfriend00

Reputation: 708026

Here's a general purpose function that would merge an arbitrary number of arrays, preventing duplicates of the passed in key.

As it is merging, it creates a temporary index of the names used so far and only merges new elements that have a unique name. This temporary index should be much faster than a linear search through the results, particularly as the arrays get large. As a feature this scheme, it filters all duplicates, even duplicates that might be in one of the source arrays.

If an element does not have the keyName, it is skipped (though that logic could be reversed if you want depending upon what error handling you want for that):

var array1 = [{ "name" : "foo" , "age" : "22"}, { "name" : "bar" , "age" : "33"}];
var array2 = [{ "name" : "foo" , "age" : "22"}, { "name" : "buz" , "age" : "35"}];

function mergeArrays(keyName /* pass arrays as additional arguments */) {
    var index = {}, i, len, merge = [], arr, name;

    for (var j = 1; j < arguments.length; j++) {
        arr = arguments[j];
        for (i = 0, len = arr.length; i < len; i++) {
            name = arr[i][keyName];
            if ((typeof name != "undefined") && !(name in index)) {
                index[name] = true;
                merge.push(arr[i]);
            }
        }
    }
    return(merge);
}

var merged = mergeArrays("name", array1, array2);

// Returns:
// [{"name":"foo","age":"22"},{"name":"bar","age":"33"},{"name":"buz","age":"35"}]

You can see it work here: http://jsfiddle.net/jfriend00/8WfFW/

When this algorithm is run against the Matt algorithm in jsperf using larger arrays, this algorithm is around 20x faster:

enter image description here

Upvotes: 5

Matt
Matt

Reputation: 75327

What you have are completely different objects, and there is nothing built into JavaScript to detect identical objects; i.e. objects which have the same attributes, so we have to write our own function:

function merge(set1, set2) {
    // Already put the elements of set1 in the result array
    // see Array.slice
    var result = set1.slice(0);

    // Utility function which iterates over the elements in result
    // and returns true if an element with the same name already
    // exists. false otherwise
    function exists(obj) {
        for (var i=0;i<result.length;i++) {
            if (result[i].name == obj.name) {
                return true;
            }
        }

        return false;
    }

    // Now simply iterate over the second set and add elements
    // which aren't there already using our exists() function.
    for (var i=0;i<set2.length;i++) {
        if (!exists(set2[i])) {
            result.push(set2[i]);
        }
    }

    return result;
}

You'd then call it with;

var result = merge(array1, array2);

To become more confident with object equality try the following experiment;

var a = { "test": 1 };
var b = { "test": 1 };
var aClone = a;

alert(a == a); // true
alert(a == b); // false
alert(a == aClone); // true

Upvotes: 1

DanRedux
DanRedux

Reputation: 9359

The first way I can think of:

array3 = [];
for(object in array1) {
    var match=false;
    for(already in array3) {
        if (already==object) {
            match=true;
            break; } }
    if (match) array3.push(object); }

Upvotes: -2

Aldo Stracquadanio
Aldo Stracquadanio

Reputation: 6237

I don't think that plain javascript offers anything better than iterating the array's and manually implementing the logic for that. What I would advice is to use the awesome underscore.js library that provides many functional-like facilities to handle arrays and collections in general; to solve your problem for example this could work:

http://documentcloud.github.com/underscore/#union

jQuery is another option, but it is more a DOM-manipulation browser-oriented library, while underscore is made to deal with these kind of problems.

Upvotes: 0

Related Questions