Объединение / расширение массивов объектов JavaScript на основе объединения ключевого свойства в каждом - PullRequest
4 голосов
/ 19 мая 2011

Я хочу объединить следующие массивы объектов, сначала присоединившись к свойству id

var arr1 = [{
    id: 1,
    name: 'fred',
    title: 'boss'
},{
    id: 2,
    name: 'jim',
    title: 'nobody'
},{
    id: 3,
    name: 'bob',
    title: 'dancer'
}];

var arr2 = [{
    id: 1,
    wage: '300',
    rate: 'day'
},{
    id: 2,
    wage: '10',
    rate: 'hour'
},{
    id: 3,
    wage: '500',
    rate: 'week'
}];

Таким образом, результат будет

[{
    id: 1,
    name: 'fred',
    title: 'boss',
    wage: '300',
    rate: 'day'
},{
    id: 2,
    name: 'jim',
    title: 'nobody',
    wage: '10',
    rate: 'hour'
},{
    id: 3,
    name: 'bob',
    title: 'dancer',
    wage: '500',
    rate: 'week'
}]

Я бы хотел избежать использования каркасов js (если это возможно), хотя ExtJs уже является частью проекта. В настоящий момент у меня есть цикл с внутренним циклом, который, если ключи совпадают, копирует свойства и прерывает внутренний цикл, чтобы запустить следующий внешний цикл.

Есть лучшие предложения?

Ответы [ 2 ]

4 голосов
/ 19 мая 2011

Как это?

var combined = [];
function findSecond(id,second){
    for (var i=0;i<second.length;i++){
        if(second[i].id === id){
            return second[i];
        }
    }
    return null
}

while (el = arr1.pop()){
    var getSec = findSecond(el.id,arr2);
    if (getSec){
        for (var l in getSec){
            if (!(l in el)) {
                el[l] = getSec[l];
            }
        }
        combined.push(el);
    }
}

Если массивы имеют одинаковую длину, а идентификаторы равны, будет выполнено более простое слияние:

function merge(a1,a2) {
    var i = -1;
    while ((i = i+1)<a1.length)  {
     for (var l in a2[i]) {
            if (!(l in a1[i] )) {
                a1[i][l] = a2[i][l];
            }
     }
    }
   return a1; 
}

Вот рабочаяпример

[ Редактировать 2016/07/30 ] Добавлен фрагмент с более функциональным подходом и, на основе комментария @djangos, дополнительный метод для объединения обоих массивы.

(function() {
    var alert = function(str) {document.querySelector('#result').textContent += str + '\n';};
    var arrays = getArrays();
  
    alert('Combine on id (shared id\'s):')
    alert(JSON.stringify(combineById(arrays.arr1, arrays.arr2), null, ' '));
  
    alert('\nCombine on id (all id\'s):')
    alert(JSON.stringify(combineBothById(arrays.arr1, arrays.arr2), null, ' '));
  
    // for combineBothById the parameter order isn't relevant
    alert('\nCombine on id (all id\'s, demo parameter order not relevant):')
    alert(JSON.stringify(combineBothById(arrays.arr2, arrays.arr1), null, ' '));
  
    // combine first array with second on common id's
    function combineById(arr1, arr2) {
      return arr1.map(
          function (el) {
                var findInB = this.filter(function (x) {return x.id === el.id;});
                if (findInB.length) {
                    var current = findInB[0];
                    for (var l in current) {
                        if (!el[l]) {el[l] = current[l];}
                    }
                }
                return el;
          }, arr2);
    }

    // combine first array with second on all id's
    function combineBothById(arr1, arr2) {
        var combined = arr1.map(
            function (el) {
                var findInB = this.filter(function (x) {return x.id === el.id;});
                if (findInB.length) {
                    var current = findInB[0];
                    for (var l in current) {
                        if (!el[l]) {el[l] = current[l];}
                    }
                }
                return el;
            }, arr2);
        combined = combined.concat(arr2.filter(
            function (el) {
                return !this.filter(function (x) {return x.id === el.id;}).length;
            }, combined));
        return combined;
    }
  
    function getArrays() {
        return {
            arr1: [{
                id: 1,
                name: 'fred',
                title: 'boss'
            }, {
                id: 2,
                name: 'jim',
                title: 'nobody'
            }, {
                id: 3,
                name: 'bob',
                title: 'dancer'
            }],
            arr2: [{
                id: 1,
                wage: '300',
                rate: 'day'
            }, {
                id: 2,
                wage: '10',
                rate: 'hour'
            }, {
                id: 4,
                wage: '500',
                rate: 'week'
            }]
        };
    }
}());
2 голосов
/ 23 декабря 2014

Вы можете объединить два массива по столбцу id с помощью библиотеки Alasql :

var res = alasql('SELECT * FROM ? arr1 JOIN ? arr2 USING id', [arr1,arr2]);

Попробуйте этот пример в jsFiddle .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...