【问题标题】:merge array with unique keys使用唯一键合并数组
【发布时间】:2018-09-03 11:41:54
【问题描述】:

我有一个名为 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]}
];

我想以这样一种方式合并两个数组,即只要两个数组中的 name 和 label 相等,它就应该只考虑 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;
}

但我没有得到正确的结果。

有什么建议吗?

【问题讨论】:

  • 你能举例说明你的预期结果吗?
  • @InstilledBee 感谢您的建议。添加示例
  • 如果你有一个对象存在于newArray 但不存在于oldArray 中,那它应该出现在最终结果中吗?
  • 你得到了什么结果?
  • newArray 中的重复项怎么样?是否可以?它们应该在最终数组中还是应该只有唯一值?

标签: javascript algorithm lodash


【解决方案1】:

您可以添加所有数组并检查 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; }

【讨论】:

  • 您可能应该指定这将丢弃newArray 中可能存在的重复项,这可能是也可能不是预期的结果。
  • @ChatterOne,我认为单个数组中没有重复项。否则,区分新旧数据是没有意义的。
  • 对你有意义的东西可能对 OP 没有意义,反之亦然。我并不是说这是错误的,我只是说最好明确说明使用此代码删除的重复项。
  • @ChatterOne 是的,newArray 中没有重复项。
【解决方案2】:

您可以简单地使用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));

【讨论】:

    【解决方案3】:

    在你的第一个 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));

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          创建一个对象,键为namelabel。现在,首先将所有oldData 记录添加到对象中,然后将newData 记录添加到对象中。如果有任何与namelabel 相同的对象,它将覆盖旧的数据值。最后得到合并后的数据集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);

          【讨论】:

          • 如果您有 name: 'ab', label: 'cde'name: 'abc', label: 'de',则不会工作。您必须创建一个哈希。
          • @aloisdg - 同意。谢谢你。更新
          【解决方案7】:

          替代方案:使用Map 作为reducer 中的初始值。您应该知道(如在所选答案中)您在这里丢失了信息,因为您没有比较数组元素中的 values 属性。所以名称/标签对test/testlabel 的对象之一将在合并的Array 中丢失。如果 sn-p 中的串联是相反的(所以newArray.concat(oldArray),合并后的Array 中的test/testLabel Object 将包含另一个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);

          【讨论】:

            【解决方案8】:
            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);
            

            【讨论】:

              猜你喜欢
              • 2022-01-27
              • 2020-06-28
              • 1970-01-01
              • 2021-04-25
              • 1970-01-01
              • 2012-08-20
              • 2018-11-03
              • 1970-01-01
              • 2020-02-02
              相关资源
              最近更新 更多