0

I have asked this question before, but it seems the solution doesn't work well.

I have two objects:

var a = [{ x: 0, y: 0, color: "green", value: undefined, weight: 1 }, { x: 0, y: 1, color:   "red", value: undefined, weight: 1 }];

var b = [{ x: 0, y: 0, value: 1}, { x: 0, y: 1, value: 3}];

I want to join them into a single object, like this:

var c = [{ x: 0, y: 0, color: "green", value: 1, weight: 1 }, { x: 0, y: 1, color: "red", value: 3, weight: 1 }];

Note: array A will always have 25 entries, while array b not.

The proposed solution was: var extendedArray = $.extend({}, a, b);

However this makes an array of two entries, where not all values are preserved.

I have also tried the following functions:

var e = $.merge(a, b);
var output = a.concat(b);

function jsonConcat(o1, o2) {
    for (var key in o2) {
        o1[key] = o2[key];
    }
    return o1;
}



var c = {};
c = jsonConcat(c, a);
c = jsonConcat(c, b);

Any help or push in the right direction would be very much appreciated!

Jef
  • 791
  • 1
  • 18
  • 36
  • What if b[0].weight == 2? Which would take precedence? – Josh Horowitz Aug 01 '14 at 07:57
  • Not possible, the weight will always be 1 if x: 0 and y: 0 on both objects. – Jef Aug 01 '14 at 08:17
  • What is supposed to happen if a has n values and b has j values? How should they merge if n > j? How about if j > n? – Josh Horowitz Aug 01 '14 at 09:32
  • `b` will never have more values than `a` , but it is likely that `a` has more values than `b`. The values of `a` should be kept, while it is important that the `value` fields from `b` are added to `object a`. I hope you still understand it, thanks for your help. – Jef Aug 01 '14 at 09:37
  • Got it. I updated my answer and tested it on the sample you provided on jsfiddle – Josh Horowitz Aug 01 '14 at 09:45

3 Answers3

1

$.extend without the first argument set to true will only merge the "first level" of your objects. It works if your properties are only strings and numbers, but if some properties are objects, it can result in unexpected behaviour.

I think you're looking for $.extend(true,obj1,obj2) .

example

var a = [{ x: 0, y: 0, color: "green", value: undefined, weight: 1 }, { x: 0, y: 1, color:   "red", value: undefined, weight: 1 }];

var b = [{ x: 0, y: 0, value: 1, weight: 1 }, { x: 0, y: 1, value: 3, weight: 1 }];

var c = $.extend(true,[],a,b);
console.log(c instanceof Array); // true

see the doc for details

the first argument true tells the method to perform a "deep" copy, recursively.

Camille Hodoul
  • 376
  • 2
  • 13
  • 1
    $.extend returns an object not an array. – Josh Horowitz Aug 01 '14 at 08:46
  • I have made an jsfiddle where I am trying to show the problem: http://jsfiddle.net/RsB33/1/ as you can see in the console, not all values have been preserved and somehow object {x:4, y:4, ... } appears twice. Any idea why? – Jef Aug 01 '14 at 08:51
1

Assuming that the two arrays have the same length, an in place merge could be something like this:

var a = [{ x: 0, y: 0, color: "green", value: undefined, weight: 1 }, { x: 0, y: 1, color:   "red", value: undefined, weight: 1 }];

var b = [{ x: 0, y: 0, value: 1, weight: 1 }, { x: 0, y: 1, value: 3, weight: 1 }];


function merge_objects(o1, o2) {
    Object.keys(o2).forEach(
        function(key) {
            o1[key] = o2[key];
        });
}

function merge(a, b) {
    if (a.length != b.length) {
        throw new Error();
    }
    for (var ix=0; ix<a.length; ix++) {
        merge_objects(a[ix], b[ix]);
    }
}
dvd
  • 1,014
  • 6
  • 12
  • Sorry forgot to add. Array a will always have the same length, but array b not. – Jef Aug 01 '14 at 08:22
1

Edited to reflect that b can be smaller but never larger than a.

function merge(a,b){
    //Don't want to mutate a
    var result = a.slice();
    for(var i = 0; i < b.length; i++){
        for (var attrname in b[i]) {
             result[i][attrname] = b[i][attrname]; 
         }
    }
    return result;
}

Code partly taken from accepted answer in: How can I merge properties of two JavaScript objects dynamically?

Community
  • 1
  • 1
Josh Horowitz
  • 655
  • 2
  • 6
  • 15
  • Thank you for your help and time. Tried to implement your function with the fiddle, but it seems to not overwrite values. If you check the fiddle (http://jsfiddle.net/RsB33/2/) with your function, the last entry should be: `color: "red", value: 1, weight: 5, x: 4, y: 4`. But the value is still undefined, any idea why this is? – Jef Aug 01 '14 at 10:01
  • 1
    Unless I have misunderstood how you expect this to work, it should be undefined because b.length is 16 and a.length is 25 so it only merges into the first 16 of a. What do you expect to happen with 17-25? – Josh Horowitz Aug 01 '14 at 11:28