用唯一键合并数组

时间:2018-09-03 11:41:55

标签: javascript algorithm lodash

我有名为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 :(得分:3)

您可以添加所有数组,并检查是否在插入Set之前插入了name / label对。

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; }

答案 1 :(得分:1)

在您的第一个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;
}

ij始终具有相同的值,您只比较数组中相同位置的条目。如果它们的长度不同,则在较短的数组结束后停止比较。仅当newArray大于oldArray时,才会执行第二个while循环。

一种可能的解决方案是复制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));

答案 2 :(得分:1)

您可以简单地使用Array.reduce()通过名称和标签的组合来创建旧Array和组的映射。要遍历新数组的所有元素或对象,并检查映射是否包含具有给定键(名称和标签的组合)的条目,如果它包含的内容不只是使用新数组对象的值更新其值,则添加它到地图。地图上的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));

答案 3 :(得分:1)

您可以复制原始数组,并在第一个数组中进行复制,或者更改元素,或者添加:

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/]

答案 4 :(得分:1)

这是使用经典的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);

答案 5 :(得分:0)

创建一个对象,其键为namelabel。现在,首先将所有oldData记录添加到对象,然后在对象中添加newData记录。如果有相同namelabel相同的任何对象,它将覆盖旧的Data值。最后,获取作为合并数据集的Object的值。

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);

答案 6 :(得分:0)

替代方法:在简化器中使用Map作为初始值。您应该知道(如在选定的答案中一样)您在此处失去了信息,因为您没有在数组元素内的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);属性值。

this

答案 7 :(得分:0)

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);