объединить массив с уникальными ключами - PullRequest
0 голосов
/ 03 сентября 2018

У меня есть массив объектов с именами newArray и oldArray.

Как это: [{name: 'abc', label: 'abclabel', values: [1,2,3,4,5]}]

example : 
newArray = [
{name: 'abc', label: 'abclabel', values: [1,2,3,4,5]}, 
{name: 'test', label: 'testlabel', values: [1,2,3,4]}
]

oldArray = [
{name: 'oldArray', label: 'oldArrayLabel', values: [1,2,3,4,5]}, 
{name: 'test', label: 'testlabel', values: [1,2,3,4,5]}
]

result will be = [
{name: 'abc', label: 'abclabel', values: [1,2,3,4,5]}, 
{name: 'test', label: 'testlabel', values: [1,2,3,4]}, 
{name: 'oldArray', label: 'oldArrayLabel', values: [1,2,3,4,5]}
];

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

Я пытался

function mergeArrayWithLatestData (newData, oldData) {
  let arr = [];
  let i = 0; let j =0
  while ((i < newData.length) && (j < oldData.length)) {
    if ((findIndex(newData, { name: oldData[i].name, label: oldData[i].label })) !== -1) {
      arr.push(newData[i])
  } else {
    arr.push(newData[i]);
    arr.push(oldData[i]);
  }
  i += 1;
  j += 1;
}
while (i < newData.length) {
    arr.push(newData[i]);
 }
 return arr;
}

Но я не получаю правильный результат.

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

Ответы [ 8 ]

0 голосов
/ 03 сентября 2018
function mergeArray(newArray, oldArray) {
      var tempArray = newArray;

      oldArray.forEach(oldData => {
        var isExist = tempArray.findIndex(function (newData) {
          return oldData.name === newData.name;
        });
        if (isExist == -1) {
          tempArray.push(oldData);
        }
      });

      return tempArray;
    }

    var newArray = [{
      name: 'abc',
      label: 'abclabel',
      values: [1, 2, 3, 4, 5]
    }, {
      name: 'test',
      label: 'testlabel',
      values: [1, 2, 3, 4]
    }];
    var oldArray = [{
      name: 'oldArray',
      label: 'oldArrayLabel',
      values: [1, 2, 3, 4, 5]
    }, {
      name: 'test',
      label: 'testlabel',
      values: [1, 2, 3, 4, 5]
    }];

    var resultArray = [];
    resultArray = mergeArray(newArray, oldArray);
    console.log(resultArray);
0 голосов
/ 03 сентября 2018

Альтернатива: использование Map в качестве начального значения в редукторе. Вы должны знать, что (как в выбранном ответе) вы теряете информацию здесь, потому что вы не сравниваете свойство values в элементах массива. Таким образом, один из объектов с парой имя / метка test/testlabel будет потерян в объединенном Array. Если бы конкатенация во фрагменте была наоборот (то есть newArray.concat(oldArray), test/testLabel Object в объединенном Array будет содержать другое значение свойства values.

const newArray = [
  {name: 'abc', label: 'abclabel', values: [1,2,3,4,5]}, 
  {name: 'test', label: 'testlabel', values: [1,2,3,4]}
];

const oldArray = [
  {name: 'oldArray', label: 'oldArrayLabel', values: [1,2,3,4,5]}, 
  {name: 'test', label: 'testlabel', values: [1,2,3,4,5]}
];

const merged = [ 
  ...oldArray.concat(newArray)
      .reduce( (map, value) => 
          map.set(`${value.name}${value.label}`, value), 
          new Map())
  .values()
];
  
console.log(merged);
0 голосов
/ 03 сентября 2018

Это использование классического filter() и сравнение названия / метки с сохранением различных пар с использованием просто +. Используя назначение деструктурирования, мы объединяем два массива, сохраняя самые новые, поэтому, когда мы проверяем другое, самое новое - это всегда оставшиеся.

var newArray = [{ name: "abc", label: "abclabel", values: [1, 2, 3, 4, 5] },{ name: "test", label: "testlabel", values: [1, 2, 3, 4] }];

var oldArray = [{ name: "oldArray", label: "oldArrayLabel", values: [1, 2, 3, 4, 5] },{ name: "test", label: "testlabel", values: [1, 2, 3, 4, 5] }];

var diff = [];

oldArray = [...newArray, ...oldArray].filter(e => {

  if (diff.indexOf(e.name + e.label) == -1) {
    diff.push(e.name + e.label);
    return true;
  } else {
    return false; //<--already exist in new Array (the newest)
  }

});

console.log(oldArray);
0 голосов
/ 03 сентября 2018

Вы делаете копии исходных массивов, а в первом или меняете элемент, или добавляете:

function mergeArrayWithLatestData (a1, a2) {
  var out = JSON.parse(JSON.stringify(a1))
  var a2copy = JSON.parse(JSON.stringify(a2))
  a2copy.forEach(function(ae) {
    var i = out.findIndex(function(e) {
        return ae.name === e.name && ae.label === e.label
    })
    if (i!== -1) {
        out[i] = ae
    } else {
        out.push(ae)
    }
  })
  return out
}

[https://jsfiddle.net/yps8uvf3/]

0 голосов
/ 03 сентября 2018

Вы можете просто использовать Array.reduce() для создания карты старого массива и группы по комбинации имени и метки. Затем выполните итерации по всем элементам или объектам нового массива и проверьте, содержит ли карта запись с данным ключом (комбинация имени и метки), если она содержит, чем просто обновите ее значения значениями нового объекта массива, иначе добавьте его на карту. Object.values() на карте даст вам желаемый результат.

let newArray = [ {name: 'abc', label: 'abclabel', values: [1,2,3,4,5]}, {name: 'test', label: 'testlabel', values: [1,2,3,4]} ];

let oldArray = [ {name: 'oldArray', label: 'oldArrayLabel', values: [1,2,3,4,5]}, {name: 'test', label: 'testlabel', values: [1,2,3,4,5]} ];

let map = oldArray.reduce((a,curr)=>{
  a[curr.name +"_" + curr.label] = curr;
  return a;
},{});

newArray.forEach((o)=> {
  if(map[o.name +"_" + o.label])
    map[o.name +"_" + o.label].values = o.values;
  else
    map[o.name +"_" + o.label] = o;
});
console.log(Object.values(map));
0 голосов
/ 03 сентября 2018

Вы можете добавить весь массив с проверкой, если пары name / label были вставлены ранее с Set.

var newArray = [{ name: 'abc', label: 'abclabel', values: [1, 2, 3, 4, 5] }, { name: 'test', label: 'testlabel', values: [1, 2, 3, 4] }],
    oldArray = [{ name: 'oldArray', label: 'oldArrayLabel', values: [1, 2, 3, 4, 5] }, { name: 'test', label: 'testlabel', values: [1, 2, 3, 4, 5] }],
    result = [newArray, oldArray].reduce((s => (r, a) => {
        a.forEach(o => {
            var key = [o.name, o.label].join('|');
            if (!s.has(key)) {
                r.push(o);
                s.add(key);
            }
        });
        return r;
    })(new Set), []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
0 голосов
/ 03 сентября 2018

В вашем первом цикле while

while ((i < newData.length) && (j < oldData.length)) {
  if ((findIndex(newData, { name: oldData[i].name, label: oldData[i].label })) !== -1) 
  {
    arr.push(newData[i])
  } else {
    arr.push(newData[i]);
    arr.push(oldData[i]);
  }
  i += 1;
  j += 1;
}

i и j всегда имеют одинаковое значение, вы сравниваете записи только в тех же позициях в массивах. Если они имеют разную длину, вы прекращаете сравнение после окончания более короткого массива. Ваш второй цикл while будет выполняться, только если newArray больше oldArray.

Одно из возможных решений - скопировать oldArray, затем выполнить итерацию по newArray и проверить, существует ли такое же значение.

function mergeArrayWithLatestData (newData, oldData) {
  let arr = oldData;
  for(let i = 0; i < newData.length; i++) {
    let exists = false;
    for(let j = 0; j < oldData.length; j++) {
      if(newData[i].name === oldData[j].name && newData[i].label === oldData[j].label) {
        exists = true;
        arr[j] = newData[i];
      }
    }
    if(!exists) {
      arr.push(newData[i]);
    }
  }
  return arr;
}

var newArray = [
{name: 'abc', label: 'abclabel', values: [1,2,3,4,5]}, 
{name: 'test', label: 'testlabel', values: [1,2,3,4]}
]

var oldArray = [
{name: 'oldArray', label: 'oldArrayLabel', values: [1,2,3,4,5]}, 
{name: 'test', label: 'testlabel', values: [1,2,3,4,5]}
]

console.log(mergeArrayWithLatestData(newArray, oldArray));
0 голосов
/ 03 сентября 2018

Создайте объект с ключом name и label. Теперь сначала добавьте все записи oldData к объекту, а затем добавьте записи newData в объект. Если есть какие-либо общие объекты с одинаковыми name и label, он перезапишет старое значение Data. Наконец, получите значения объекта, который является объединенным набором данных.

var arr1 = [{name: 'def', label: 'abclabel', values: [6,7]}, {name: 'abc', label: 'abclabel', values: [1,2,3,4,5]}];
var arr2 = [{name: 'xy', label: 'abclabel', values: [6,7]}, {name: 'abc', label: 'abclabel', values: [6,7]}];

function mergeArrayWithLatestData(newData, oldData) {
  var result = {};
  [...oldData, ...newData].forEach(o => result[o.name + "~~$$^^" + o.label] = o);
  return Object.values(result);
}

let result = mergeArrayWithLatestData(arr1, arr2);
console.log(result);
...