深度合并嵌套数组

时间:2016-11-21 03:40:05

标签: javascript arrays

我必须将2个数组与键值合并,如下所示:

array1 = [
{id:"123", data:[{id:"234",data:"hello"},{id:"345",data:"there"},{id:"xyz", data:"yo"}]},
{id:"456", data:[{id:"34",data:"test"},{id:"45",data:"test2"},{id:"yz", data:"test3"}]},
{id:"789", data:[{id:"23",data:"aaa"},{id:"34",data:"bbb"},{id:"xy", data:"ccc"}]}]

array2 = [
{id:"456", data:[{id:"45",data:"changed"},{id:"yz", data:"data"}]},
{id:"789", data:[{id:"456",data:"appended data"}]},
{id:"890", data:[{id:"456",data:"new data"}]}]

生成像

这样的东西
merged = [
{id:"123", data:[{id:"234",data:"hello"},{id:"345",data:"there"},{id:"xyz", data:"yo"}]},
{id:"456", data:[{id:"34",data:"test"},{id:"45",data:"changed"},{id:"yz", data:"data"}]},
{id:"789", data:[{id:"23",data:"aaa"},{id:"34",data:"bbb"},{id:"xy", data:"ccc"},{id:"456",data:"appended data"}]},
{id:"890", data:[{id:"456",data:"new data"}]}]

我已经尝试了很长时间,并且无法获得符合该方案的解决方案。大多数解决方案只是盲目合并,而不是基于id值。尝试使用lodash mergeWith,但没有得到所需的输出。 Ramda解决方案也是可以接受的。

谢谢,

3 个答案:

答案 0 :(得分:0)

此链接可能对您有所帮助merge two arrays

在这个代码片段中,我试图找到set1和set2之间的公共对象,如果有任何我找到了唯一的属性并更改了它们的内容以及object2中不存在的属性并将其推送到object1

检查以下代码段。

var arr1 = [{
  id: "123",
  data: [{
    id: "234",
    data: "hello"
  }, {
    id: "345",
    data: "there"
  }, {
    id: "xyz",
    data: "yo"
  }]
}, {
  id: "456",
  data: [{
    id: "34",
    data: "test"
  }, {
    id: "45",
    data: "test2"
  }, {
    id: "yz",
    data: "test3"
  }]
}, {
  id: "789",
  data: [{
    id: "23",
    data: "aaa"
  }, {
    id: "34",
    data: "bbb"
  }, {
    id: "xy",
    data: "ccc"
  }]
}]

var arr2 = [{
  id: "456",
  data: [{
    id: "45",
    data: "changed"
  }, {
    id: "yz",
    data: "data"
  }]
}, {
  id: "789",
  data: [{
    id: "456",
    data: "appended data"
  }]
}, {
  id: "890",
  data: [{
    id: "456",
    data: "new data"
  }]
}]
var arr3 = [];
for (var i in arr1) {
  var shared = false;
  for (var j in arr2)
    if (arr2[j].id == arr1[i].id) {
      shared = true;
      //  arr1[i].data.concat(arr2[j].data);
      var set1 = pushproperties(arr1[i].data, arr2[j].data);
      arr1[i].data = set1;
      arr3.push(arr1[i]);
      break;
    }
  if (!shared) {
    arr3.push(arr1[i]);
    arr3.push(arr2[j]);
  }

}

function pushproperties(set1, set2) {
  var filtered = false;
  set2.forEach(function(item) {
    filtered = set1.every(function(element) {
      return element.id != item.id;

    });
    if (filtered) {
      set1.push(item);
    }

  });

  set1.forEach(function(item) {
    set2.forEach(function(element) {
      if (item.id == element.id) {
        item.data = element.data;
      }

    });


  });

  return set1;

}

console.log(arr3);

希望这有帮助

答案 1 :(得分:0)

这个函数使用Array.prototype.reduce()递归地合并2个数组。如果它遇到具有相同id的项目,并且它们有一个data prop,它是一个数组,它会使用逻辑合并它们。如果data不是数组,则会被最后一项覆盖。

function mergeArraysDeep(arr1, arr2) { 
  var unique = arr1.concat(arr2).reduce(function(hash, item) {
    var current = hash[item.id];
    
    if(!current) {
      hash[item.id] = item;
    } else if (Array.isArray(current.data)) {
      current.data = mergeArraysDeep(current.data, item.data);
    } else {
      current.data = item.data;
    }

    return hash;
  }, {});

  return Object.keys(unique).map(function(key) {
    return unique[key];
  });
}

var array1 = [
  {id:"123", data:[{id:"234",data:"hello"},{id:"345",data:"there"},{id:"xyz", data:"yo"}]},
  {id:"456", data:[{id:"34",data:"test"},{id:"45",data:"test2"},{id:"yz", data:"test3"}]},
  {id:"789", data:[{id:"23",data:"aaa"},{id:"34",data:"bbb"},{id:"xy", data:"ccc"}]}
];

var array2 = [
  {id:"456", data:[{id:"45",data:"changed"},{id:"yz", data:"data"}]},
  {id:"789", data:[{id:"456",data:"appended data"}]},
  {id:"890", data:[{id:"456",data:"new data"}]}
];

var result = mergeArraysDeep(array1, array2)

console.log(result);

使用MapMap.prototype.values()array spread的ES6版本:

const mergeArraysDeep = (arr1, arr2) => { 
  return [...arr1.concat(arr2).reduce((hash, item) => {
    const current = hash.get(item.id);
    
    if(!current) {
      hash.set(item.id, item);
    } else if (Array.isArray(current.data)) {
      current.data = mergeArraysDeep(current.data, item.data);
    } else {
      current.data = item.data;
    }

    return hash;
  }, new Map()).values()];
}

const array1 = [
  {id:"123", data:[{id:"234",data:"hello"},{id:"345",data:"there"},{id:"xyz", data:"yo"}]},
  {id:"456", data:[{id:"34",data:"test"},{id:"45",data:"test2"},{id:"yz", data:"test3"}]},
  {id:"789", data:[{id:"23",data:"aaa"},{id:"34",data:"bbb"},{id:"xy", data:"ccc"}]}
];

const array2 = [
  {id:"456", data:[{id:"45",data:"changed"},{id:"yz", data:"data"}]},
  {id:"789", data:[{id:"456",data:"appended data"}]},
  {id:"890", data:[{id:"456",data:"new data"}]}
];

const result = mergeArraysDeep(array1, array2)

console.log(result);

答案 2 :(得分:0)

最后这对我有用。感谢@Geeky展示道路:

function mergeArrays(arr1, arr2) {
  var arr3, arrIdx = [];
  if (!arr1 || arr1.length ==0) return arr2
  for (var i in arr1) {
    var shared = false;
    for (var j in arr2)
      if (arr2[j].id == arr1[i].id) {
        shared = true;
        joined = _.mergeWith({},arr1[i],arr2[j], function (a,b) {
          if (_.isArray(a)) return b.concat(a)})
        arr3.push(joined);
        break;
      }
    if (!shared) {
      arr3.push(arr1[i]);
    }
  }
  for (var k in arr2) {
    if (arrIdx[k] !=k) arr3.push(arr2[k])
  }
  return arr3

}