k00k
k00k

Reputation: 17573

Using Javascript and Underscore.js, how can I compare 2 arrays and replace properties if a match?

I have 2 arrays like so:

var arrayOne = [
    {page:'1',tags:['foo','bar']},
    {page:'2',tags:['oh','boy']}
];
var arrayTwo = [
    {page:'1',tags:['go','out']},
    {page:'9b',tags:['red','blue','green']}
];

I want to compare the two arrays, and if the page property is the same, replace the tags property in arrayOne with the tags property from arrayTwo.

So given the example arrays above, only the tags for page: 1 of arrayOne would get replaced with page: 1's values from arrayTwo.

I'm thinking I can do this with underscore.js, but I'm struggling to see how.

Ideas?

Upvotes: 1

Views: 3436

Answers (3)

k00k
k00k

Reputation: 17573

I was able to do what I needed by using Underscore's _each by doing one inside of another like so ( http://jsfiddle.net/4JP7g/ ) :

var arrayOne = [
    {page:1,tags:["foo","bar"]},
    {page:2,tags:["oh","boy"]}
];
var arrayTwo = [
    {page:1,tags:["go","out"]},
    {page:9,tags:["red","blue","green"]}
];

_.each(arrayOne, function(one){
    _.each(arrayTwo, function(two){
      if(one.page === two.page){
                one.tags = two.tags;  
                console.log (one.tags);            
      }           
    });
});​

Upvotes: 0

mu is too short
mu is too short

Reputation: 434665

If you actually have two arrays of JavaScript objects like this:

var a1 = [
    {page: '1', tags: ['foo', 'bar']},
    {page: '2', tags: ['oh',  'boy']},
    //...
];
var a2 = [
    {page: '1',  tags: ['go', 'out']},
    {page: '9b', tags: ['red', 'blue', 'green']},
    //...
];

Then I'd convert a2 to a page-to-tags lookup table:

var lookup = { }, i, e;
for(i = 0, e = a2[i]; i < a2.length; e = a2[++i])
    lookup[e.page] = e.tags;

and then spin through a1 merging in lookup values as you go:

for(i = 0, e = a1[i]; i < a1.length; e = a1[++i])
    e.tags = lookup[e.page] || e.tags;

Demo: http://jsfiddle.net/ambiguous/aDgH7/

If you must use Underscore, you could replace the loops with _.reduce and _.each:

var lookup = _(a2).reduce(function(lookup, e) {
    lookup[e.page] = e.tags;
    return lookup;
}, { });
_(a1).each(function(e) {
    e.tags = lookup[e.page] || e.tags;
});

Demo: http://jsfiddle.net/ambiguous/rkMZz/

If you could assume a modernish JavaScript, then the standard reduce and forEach array methods could be used:

var lookup = a2.reduce(function(lookup, e) {
    lookup[e.page] = e.tags;
    return lookup;
}, { });
a1.forEach(function(e) {
    e.tags = lookup[e.page] || e.tags;
});

Demo: http://jsfiddle.net/ambiguous/cy2Qy/

If you actually have arrays of JSON strings then you can mix in JSON.parse and JSON.stringify calls to unpack and repack the data.

Upvotes: 1

jAndy
jAndy

Reputation: 236022

like

var arrayOne = [
    '{"page":"1","tags":["foo","bar"]}',
    '{"page":"2","tags":["oh","boy"]}'
];
var arrayTwo = [
    '{"page":"1","tags":["go","out"]}',
    '{"page":"9b","tags":["red","blue","green"]}'
];

var maxLen = Math.max( arrayOne.length, arrayTwo.length ),
    objA, objB;

while( maxLen-- ) {
    objA = JSON.parse( arrayOne[ maxLen ] );
    objB = JSON.parse( arrayTwo[ maxLen ] );

    if( objA.page === objB.page ) {
        objA.tags = objB.tags
        arrayOne[ maxLen ] = JSON.stringify( objA );
    }
}

This is pretty much a perfect world example. It becomes a little bit more tricky if Array one and two do not contain the same amount of items.

Upvotes: 0

Related Questions