1

Suppose I have the following arrays:

var first = [
    { id: 1, name: 'first' },
    { id: 2, name: 'second' },
    { id: 3, name: 'third' }
]

var second = [
    { id: 2, field: 'foo2' },
    { id: 3, field: 'foo3' },
    { id: 4, field: 'foo4' }
]

var third = [
    { id: 2, data: 'some2' },
    { id: 5, data: 'some5' },
    { id: 6, data: 'some6' }
]

I want to merge them to get the following result:

var result = [
    { id: 1, name: 'first',   field: undefined, data: undefined },
    { id: 2, name: 'second',  field: 'foo2',    data: 'some2' },
    { id: 3, name: 'third',   field: 'foo3',    data: undefined },
    { id: 4, name: undefined, field: 'foo4',    data: undefined },
    { id: 5, name: undefined, field: undefined, data: 'some5' },
    { id: 6, name: undefined, field: undefined, data: 'some6' }
]

How could I do it with JavaScript?

thefourtheye
  • 206,604
  • 43
  • 412
  • 459
JuniorThree
  • 143
  • 7
  • 1
    possible duplicate of [How to merge two arrays in Javascript and de-duplicate items](http://stackoverflow.com/questions/1584370/how-to-merge-two-arrays-in-javascript-and-de-duplicate-items) – Krzysztof Trzos Apr 22 '15 at 10:01
  • `concat` won't do it. He isn't just adding items, he wants the union of fields as well. Oh, whoever put in `concat` deleted the comment. Never mind mine, then. – deitch Apr 22 '15 at 10:02
  • @VigneswaranMarimuthu concat is not suitable in my case cause I wanna not simply merge arrays. I want to merge their items – JuniorThree Apr 22 '15 at 10:03
  • this link may help: http://stackoverflow.com/questions/16433605/how-do-i-union-merge-two-collections-by-their-id-using-underscorejs – BeNdErR Apr 22 '15 at 10:22

4 Answers4

0

There is no simple solution for what you want. Here is my suggestion.

var first = [
    { id: 1, name: 'first' },
    { id: 2, name: 'second' },
    { id: 3, name: 'third' }
]

var second = [
    { id: 2, filed: 'foo2' },
    { id: 3, field: 'foo3' },
    { id: 4, field: 'foo4' }
];

var third = [
    { id: 2, data: 'some2' },
    { id: 4, data: 'some4' },
    { id: 6, data: 'some6' }
];

var result = {};
first.concat(second,third).forEach(function(item){
    var id = item.id;
    var row = result[id];
    if(!row){
        result[id] = item;
        return;
    }
    for(var column in item){
        row[column] = item[column];
    }
});
var finalResult = Object.keys(result).map(function(id){
    return result[id];
});
console.log(finalResult);
Lewis
  • 11,912
  • 9
  • 59
  • 79
  • it looks nice but in finalResult I get every item with only field however i want to get union of filed fro every item. For instance First, second and third arrays contain item with id == 2 aind i want to get in finalResult the following: { id: 2, name: 'second', field: 'foo2', data: 'some2' } but i get { id: 2, name: 'second' } – JuniorThree Apr 22 '15 at 10:34
0

You should get all existed keys and after create new Objects with fill "empty" keys:

function mergeArrays(){
    var keys = {};
    //save all existed keys
    for(var i=arguments.length;--i;){
        for(var j=arguments[i].length;--j;){
            for(var key in arguments[i][j]){
                keys[key] = true;
            }
        }
    }

    var res = [];
    for(var i=arguments.length;--i;){
        for(var j=arguments[i].length;--j;){
            //set clone of object
            var clone = JSON.parse(JSON.stringify(arguments[i][j]));
            for(var key in keys){
                if(!(key in clone)){
                    clone[key] = undefined;
                }
            }
            res.push(clone);
        }
    }

    return res;
}

https://jsfiddle.net/x3b0tk3g/

Mihail
  • 1,459
  • 11
  • 13
0

There's probably a shorter way to solve this, but this covers all the steps, including ensuring that there are default properties that are undefined if not found. It also takes any number of input arrays, and you can specify what default keys you require if they're not already covered by the keys in the existing objects, so pretty future-proof for your needs.

// merges the key/values of two objects
function merge(a, b) {
    var key;
    if (a && b) {
        for (key in b) {
            if (b.hasOwnProperty(key)) {
                a[key] = b[key];
            }
        }
    }
    return a;
}

function concatenate() {
    var result = [];
    var args = arguments[0];
    for (var i = 0, l = args.length; i < l; i++) {
        result = result.concat(args[i]);
    }
    return result;
}

// return a default object
function getDefault() {
    return {
        id: undefined,
        name: undefined,
        data: undefined,
        field: undefined
    };
}

// loop over the array and check the id. Add the id as a key to
// a temporary pre-filled default object if the key
// doesn't exist, otherwise merge the existing object and the
// new object
function createMergedArray(result) {
    var temp = {};
    var out = [];
    for (var i = 0, l = result.length; i < l; i++) {
        var id = result[i].id;
        if (!temp[id]) temp[id] = getDefault();
        merge(temp[id], result[i]);
    }

    // loop over the temporary object pushing the values
    // into an output array, and return the array
    for (var p in temp) {
        out.push(temp[p]);
    }
    return out;
}

function mergeAll() {

    // first concatenate the objects into a single array
    // and then return the results of merging that array
    return createMergedArray(concatenate(arguments));
}

mergeAll(first, second, third);

DEMO

Andy
  • 39,764
  • 8
  • 53
  • 80
0

fiddle: http://jsfiddle.net/bs20jvnj/2/

 function getByProperty(arr, propName, propValue) {
        for (var i = 0; i < arr.length; i++) {
            if (arr[i][propName] == propValue) return arr[i];
        }
    }
var limit = first.length + second.length + third.length;
var res = [];
for (var i = 1; i < limit; i++) {

    var x = $.extend({}, getByProperty(first, "id", i), getByProperty(second, "id", i), getByProperty(third, "id", i));
    console.log(x["id"]);
    if (x["id"] === undefined) x["id"] = i;
    res.push(x);
}

console.log(res);
Vijay
  • 2,865
  • 1
  • 12
  • 23