Полное внешнее объединение двух массивов js, содержащих объекты - объединенный массив содержит новое свойство 'action' (add / remove / edit / same) - PullRequest
0 голосов
/ 01 апреля 2019

У меня есть два массива originalArray и modifiedArray, которые имеют объекты с некоторыми свойствами;sys_id является уникальным свойством:

originalArray = [
    { sys_id: 1234, type: 'XYZZ' }, 
    { sys_id: 1235, type: 'ABCD' }, 
    { sys_id: 1236, type: 'IJKL' },
    { sys_id: 1237, type: 'WXYZ' }, 
    { sys_id: 1238, type: 'LMNO' }
]

modifiedArray = [
    { sys_id: 1234, type: 'XYZZ' }, 
    { sys_id: 1235, type: 'ZZAA' },  
    { sys_id: 1236, type: 'ZZZZ' },
    { sys_id: 1252, type: 'AAAA' }
]

Я хочу объединить / объединить массивы, но включить новое свойство, которое описывает полный отчет о том, что изменилось в новом массиве на основе исходного массива, используясвойство sys_id.

resultingArray = [
    { sys_id: 1234, type: 'XYZZ', action: 'same' }, 
    { sys_id: 1235, type: 'ZZAA', action: 'edit' }, 
    { sys_id: 1236, type: 'ZZZZ', action: 'edit' },
    { sys_id: 1237, type: 'WXYZ', action: 'remove' }, 
    { sys_id: 1238, type: 'LMNO', action: 'remove' },
    { sys_id: 1252, type: 'AAAA', action: 'add' }

Также хотелось бы узнать, есть ли более подходящая терминология или более краткий способ объяснить, чего я здесь пытаюсь достичь?

Яна платформе, которая ограничена ES5.

Ответы [ 5 ]

1 голос
/ 01 апреля 2019

Пожалуй, это самое простое решение, и оно полностью поддерживает ES5 !
Сначала вставьте все элементы originalArray в resultingArray и включите свойство
action = 'удалить'
Кроме того, сохраните индекс элемента resultingArray в хешируемый объект, где key = sys_id

После этого переберите элементы modifiedArray и отметьте hash, если sys_id уже существует в resultingArray. Если он уже существует, сравните type. В противном случае вставьте новый элемент, где action = 'add'

Я думаю, что мой код легче понять, чем приведенное выше описание. Вот оно:

var originalArray = [{ sys_id: 1234, type: 'XYZZ' },{ sys_id: 1235, type: 'ABCD' },{ sys_id: 1236, type: 'IJKL' },{ sys_id: 1237, type: 'WXYZ' },{ sys_id: 1238, type: 'LMNO' }];

var modifiedArray = [{ sys_id: 1234, type: 'XYZZ' },{ sys_id: 1235, type: 'ZZAA' },{ sys_id: 1236, type: 'ZZZZ' },{ sys_id: 1252, type: 'AAAA' }];

var resultingArray = [],
hash = {},
index = 1;

originalArray.forEach(function(elem) {
    var item = JSON.parse(JSON.stringify(elem));
    item['action'] = 'remove';
    resultingArray.push(item);
    hash[item.sys_id] = index++;
});

modifiedArray.forEach(function(elem) {
    index = hash[elem.sys_id];
    if(index){
        var item = resultingArray[index - 1];
        item.action = (item.type === elem.type) ? 'same' : 'edit';
        return;
    }
    var item = JSON.parse(JSON.stringify(elem));
    item['action'] = 'add';
    resultingArray.push(item);
});

console.log(resultingArray);
.as-console-wrapper {max-height:100% !important; top:0px;}

Примечание. В этом решении предполагается, что все элементы originalArray уникальны и одинаковы для modifiedArray.

1 голос
/ 01 апреля 2019

Вы можете конвертировать массивы в словари.Затем итерируйте оригинал и проверьте измененный словарь, чтобы найти remove/edit/same, и итерируйте измененный и оригинальный словарь, чтобы найти add элементы.Конкататируйте результаты обеих итераций, чтобы получить результаты:

var originalArray = [{"sys_id":1234,"type":"XYZZ"},{"sys_id":1235,"type":"ABCD"},{"sys_id":1236,"type":"IJKL"},{"sys_id":1237,"type":"WXYZ"},{"sys_id":1238,"type":"LMNO"}];

var modifiedArray = [{"sys_id":1234,"type":"XYZZ"},{"sys_id":1235,"type":"ZZAA"},{"sys_id":1236,"type":"ZZZZ"},{"sys_id":1252,"type":"AAAA"}];

// create a dictionary of objects by the sys_id
function bySysId(arr) {
  return arr.reduce(function(r, o) {
    r[o.sys_id] = o;
    
    return r;
  }, {});
}

// add an action to an object
function addAction(o, action) {
  var c = {
    sys_id: o.sys_id,
    type: o.type,
    action: action
  };
  
  return c;
}

function diffArrays(original, modified) {
  var origById = bySysId(original); // create a dictionary of original by sys_id
  var modById = bySysId(modified); // create a dictionary of modified by sys_id
  
  // iterate original and action
  var modifiedOrSame = original.map(function(o) {
    var mod = modById[o.sys_id];
    
    if(!mod) return addAction(o, 'remove'); // doesn't exist in modById
    else if(mod && mod.type !== o.type) return addAction(mod, 'edit'); // exists in modified but type is different
    
    return addAction(o, 'same'); // haven't changed
  });
  
  var added = modified
    .filter(function(o) { // remove items that are in original
      return !(o.sys_id in origById);
    })
    .map(function(o) { // add the 'add' action to the items
      return addAction(o, 'add');
    });
    
  return modifiedOrSame.concat(added);
}

var result = diffArrays(originalArray, modifiedArray);

console.log(result);
1 голос
/ 01 апреля 2019

Использование Array#reduce() для создания объекта, который использует sys_id в качестве ключей и имеет свойства orig и mod, а затем старый добрый цикл for in для итерации этого объекта и сравнения двух типов, когда они существуют, или проверки, какие не существует и отправляет правильные данные в массив результатов.

Все ES5 совместимые

var grouped = [originalArray, modifiedArray].reduce(function(acc, arr, i) {
  var label = i === 0 ? 'orig' : 'mod';
  for (var j = 0; j < arr.length; j++) {
    var curr = arr[j], id = curr.sys_id;
    acc[id] = acc[id] || {orig: null, mod: null };
    acc[id][label] = curr;
  }
  return acc;
}, {});

var res = [];

function insertObj(o, act) {
  var newObj = { action: act };
  // iterate existing keys to add to new object
  for (var k in o) {
    if (o.hasOwnProperty(k)) {
      newObj[k] = o[k]
    }
  }
  res.push(newObj)
}

for (var key in grouped) {
  var action, obj;
  if (grouped.hasOwnProperty(key)) { 
    obj = grouped[key]
    if (!obj.orig) {
      insertObj(obj.mod, 'add');
    } else if (!obj.mod) {
      insertObj(obj.orig, 'remove')
    } else {
      action = obj.mod.type === obj.orig.type ? 'same' : 'edit';
      insertObj(obj.mod, action)
    }
  }
}

console.log(res)
<script>

var originalArray = [
    { sys_id: 1234, type: 'XYZZ' }, 
    { sys_id: 1235, type: 'ABCD' }, 
    { sys_id: 1236, type: 'IJKL' },
    { sys_id: 1237, type: 'WXYZ' }, 
    { sys_id: 1238, type: 'LMNO' }
]

var modifiedArray = [
    { sys_id: 1234, type: 'XYZZ' }, 
    { sys_id: 1235, type: 'ZZAA' },  
    { sys_id: 1236, type: 'ZZZZ' },
    { sys_id: 1252, type: 'AAAA' }
]
</script>
1 голос
/ 01 апреля 2019

Ничего, кроме старого доброго грубого подхода. Также важно убедиться, что в исходных входах нет мутаций. По сути, я перебираю все подряд дважды и проверяю на наличие следующих условий:

1) тот же sys_id и тип (действие: то же самое)

2) тот же sys_id, другой тип (действие: изменить)

3) другой sys_id, другой тип (действие: удалить)

4) другой идентификатор sys_id, другой тип и объект существуют в модифицированном массиве, но не существуют в исходном массиве (действие: добавление)

(мне больно писать без ES6)

var originalArray = [
    { sys_id: 1234, type: 'XYZZ' }, 
    { sys_id: 1235, type: 'ABCD' }, 
    { sys_id: 1236, type: 'IJKL' },
    { sys_id: 1237, type: 'WXYZ' }, 
    { sys_id: 1238, type: 'LMNO' }
];

var modifiedArray = [
    { sys_id: 1234, type: 'XYZZ' }, 
    { sys_id: 1235, type: 'ZZAA' },  
    { sys_id: 1236, type: 'ZZZZ' },
    { sys_id: 1252, type: 'AAAA' }
];

var resultingArray = [];

for (var i = 0; i < originalArray.length; i++) {
  for (var j = 0; j < modifiedArray.length; j++) {
    if (originalArray[i].sys_id === modifiedArray[j].sys_id && originalArray[i].type === modifiedArray[j].type) {
      resultingArray.push({
        sys_id: originalArray[i].sys_id,
        type: originalArray[i].type,
        action: 'same'
      });
      break;
    } else if (originalArray[i].sys_id === modifiedArray[j].sys_id && originalArray[i].type !== modifiedArray[j].type) {
      resultingArray.push({
        sys_id: originalArray[i].sys_id,
        type: modifiedArray[j].type,
        action: 'edit'
      });
      break;
    } else if (originalArray[i].sys_id !== modifiedArray[j].sys_id && originalArray[i].type !== modifiedArray[j].type) {
      if (i ===originalArray.length - 1 && j === modifiedArray.length - 1) {
        resultingArray.push({
          sys_id: originalArray[i].sys_id,
          type: modifiedArray[j].type,
          action: 'add'
        });
      } else if (j === modifiedArray.length - 1) {
        resultingArray.push({
          sys_id: originalArray[i].sys_id,
          type: originalArray[i].type,
          action: 'remove'
        });
      }
    }
  }
}

console.log(resultingArray);

Демо

1 голос
/ 01 апреля 2019

Выполните итерацию по первому массиву, найдите соответствующее значение во втором и на основе этого генерирующего элемента. Наконец, добавьте оставшиеся элементы как новые.

var originalArray = [{      sys_id: 1234,      type: 'XYZZ'    },    {      sys_id: 1235,      type: 'ABCD'    },    {      sys_id: 1236,      type: 'IJKL'    },    {      sys_id: 1237,      type: 'WXYZ'    },    {      sys_id: 1238,      type: 'LMNO'    }  ],
  modifiedArray = [{      sys_id: 1234,      type: 'XYZZ'    },    {      sys_id: 1235,      type: 'ZZAA'    },    {      sys_id: 1236,      type: 'ZZZZ'    },    {      sys_id: 1252,      type: 'AAAA'    }  ];
  
  
// keep a swallow copy to not effect the original one
let mA = modifiedArray.slice();

// iterate over to generate new array
let res = originalArray.map(o => {
  // get index of eleemnt
  let moi = mA.findIndex(o1 => o1.sys_id === o.sys_id); 
  // if found 
  if (moi > -1) {
    // remove it from the swallow copied array
    let mo = mA.splice(moi,1)[0];
    // check and generate new array
    return { ...mo, action: mo.type === o.type ? 'same' : 'edited' }
  } else {
    // if not found return as removed
    return { ...o, action: 'removed' }
  }
  // add remaining values as added
}).concat(mA.map(o=>({...o, action: 'added'})))

console.log(res);

ES5 альтернатива:

var originalArray = [{      sys_id: 1234,      type: 'XYZZ'    },    {      sys_id: 1235,      type: 'ABCD'    },    {      sys_id: 1236,      type: 'IJKL'    },    {      sys_id: 1237,      type: 'WXYZ'    },    {      sys_id: 1238,      type: 'LMNO'    }  ],
  modifiedArray = [{      sys_id: 1234,      type: 'XYZZ'    },    {      sys_id: 1235,      type: 'ZZAA'    },    {      sys_id: 1236,      type: 'ZZZZ'    },    {      sys_id: 1252,      type: 'AAAA'    }  ];


// function for copying properties to function
function copyProperty(from, to) {
  for (var prop in from) {
    if (from.hasOwnProperty(prop))
      to[prop] = from[prop];
  }
  return to;
}

var mA = modifiedArray.slice();

var res = originalArray.map(function(o) {
  var moi = -1;
  
  // get index by iterating
  for (var i = 0; i < mA.length; i++) {
    if (mA[i].sys_id === o.sys_id) {
      moi = i;
      break;
    }
  }
  if (moi != -1) {
    var mo = mA.splice(moi, 1)[0];
    return copyProperty(mo, { action: mo.type === o.type ? 'same' : 'edited' })
  } else {
    return copyProperty(o, { action: 'removed' })
  }
})

// push remaining values
mA.forEach(function(o) {
  res.push(copyProperty(o, { action: 'added' }))
})

console.log(res);
...