Javascript merge arrays based on common element

2019-07-20 18:18发布

问题:

I'm trying to create a single object which takes information from two separate objects (taken from ajax calls). Basically we have a list of tags, and also a list of elements, these items are related, however the tag object doesn't contain all of the information I need to populate all the data. For example:

List of tags:

[
    {"id": 1, "name": "yadda", "description": "yadda yadda"},
    {"id": 2, "name": "yadda1", "description": "yadda yadda1"},
    {"id": 7, "name": "yadda2", "description": "yadda yadda2"},
    {"id": 10, "name": "yadda3", "description": "yadda yadda3"}
]

List of Elements (more info):

[
    {"id": 1, "icon": "icon1.gif"},
    {"id": 2, "icon": "icon2.gif"},
    {"id": 7, "icon": "icon3.gif"},
    {"id": 10, "icon": "icon4.gif"}
]

I need to compare the two objects by the ID, and combine them into a new object that gives me access to all of the data in both of those objects.

If it helps, this is an angular project, and I am already using Underscore, I believe there must be some way to do this with underscore, but i'm not very familliar with it.

回答1:

Quick and dirty:

var a = [
        {"id": 1, "name": "yadda", "description": "yadda yadda"},
        {"id": 2, "name": "yadda1", "description": "yadda yadda1"},
        {"id": 7, "name": "yadda2", "description": "yadda yadda2"},
        {"id": 10, "name": "yadda3", "description": "yadda yadda3"}
    ], 
    b = [
        {"id": 1, "icon": "icon1.gif"},
        {"id": 2, "icon": "icon2.gif"},
        {"id": 7, "icon": "icon3.gif"},
        {"id": 10, "icon": "icon4.gif"}
    ];

var result = a.map(function(v){

    var ret;

    $.each(b, function(k, v2){

        if(v2.id === v.id){
            ret = $.extend({}, v2, v); // merge the objects in to a new one
            return false; // break the loop
        }      

    });

    return ret;

});

console.log(result);

http://jsfiddle.net/YwUA2/

As you can see, this assumes that there's a 1:1 relationship between the objects in the two arrays.



回答2:

http://plnkr.co/edit/77kMDeqkGvyVK87FISGl?p=info

function combine(x,y){
  var z = x;
  for (i=0; i<x.length; i++){
    for (j=0; j<y.length; j++){
      if (x[i].id === y[j].id) {
        z[i].icon = y[j].icon;
        break;
      }  
    }
  }
  return z;
}


回答3:

Seems like migration from SQL JOIN to Javascript code.

Here's a LEFT JOIN implement:

var hash2 = _.object(
    _.map(list2,function(row){ 
        return [row.id,_.omit(row,"id")]; 
    })
);
var newList = _.map(list1,function(row){ 
    return _.extend(row,hash2[row.id]||{}); 
});


回答4:

For whats its worth, no libraries, just vanilla js

Function that does the work:

function mergeObjArrays(list1, list2) {
    var mergedList = [],
    i = 0,
    j = 0,
    k = 0,
    l1 = list1.length,
    l2 = list2.length,
    listMatchFound = false,
    mergedObj,
    mergeMatchFound = false;
    for (i = 0; i < l1; i++) {
        for (j = 0; j < l2; j++) {
            if (list1[i].id === list2[j].id) {
                listMatchFound = true;
                mergedObj = mergeObj(list1[i], list2[j]);
                for (k = 0; k < mergedList.length; k++) {
                    if (mergedList[k].id === mergedObj.id) {
                        mergedObj = mergeObj(mergedList[k], mergedObj);
                        mergedList[k] = mergedObj;
                        mergeMatchFound = true;
                        break;
                    }
                }
                if (!mergeMatchFound) {
                    mergedList.push(mergedObj);
                } else {
                    mergeMatchFound = false; //reset ready for another iteration
                }
            }
        }
        if (!listMatchFound) {
            mergedList.push(list1[i]);
        } else {
            listMatchFound = false; //reset ready for another iteration
        }
    }
    return mergedList;

    function mergeObj(obj1, obj2) {
        for (var o in obj1) {
            obj2[o] = obj1[o];
        }
        return obj2;
    }
}

Example usage

var a = [
        {"id": 1, "name": "yadda", "description": "yadda yadda"},
        {"id": 2, "name": "yadda1", "description": "yadda yadda1"},
        {"id": 7, "name": "yadda2", "description": "yadda yadda2"},
        {"id": 10, "name": "yadda3", "description": "yadda yadda3"}
    ];

var b = [    
        {"id": 7, "icon": "icon3.gif"},
        {"id": 10, "icon": "icon4.gif"},
        {"id": 2, "icon": "icon2.gif"},
        {"id": 2, "title": "Number 2 title"},
        {"id": 1, "icon": "icon1.gif"}
    ];

//used like

var result = mergeObjArrays(a,b);

console.log(result)

//outputs (although not necessarily in order)
[
 {"id": 1, "name": "yadda", "description": "yadda yadda","icon": "icon1.gif"},
 {"id": 2, "name": "yadda1", "description": "yadda yadda1","icon": "icon2.gif","title": "Number 2 title"},
 {"id": 7, "name": "yadda2", "description": "yadda yadda2","icon": "icon3.gif"},
 {"id": 10, "name": "yadda3", "description": "yadda yadda3","icon": "icon4.gif"}
]   

This will ineffect do a merge based on objects in set1 (a in this example), (i.e. include object if occurs in set1, or merge object if in both set1 and set2 but not if it occurs only in set2), and deal with a 1 to many relationship as well (i.e. multiple instances of an object in set2 will be merged into one object with set1's obj) and order of the objects doesn't matter. You could even go a step further and pass in the field that is the key (common element) in both objects, in this example "id" is hardwired to the mergeObjArrays function.