将两个对象与其中的数组合并

时间:2016-02-27 00:39:01

标签: javascript arrays node.js object javascript-objects

我正在尝试合并其中包含数组和其他元素的两个javascript对象。我举个例子。

{
        "addresses": [
            {
                "type": "email",
                "tags": [
                    "Responsável",
                    "Pai"
                ],
                "address": "johndoepai1@gmail.com"
            },
            {
                "type": "phone",
                "tags": [
                    "Responsável",
                    "Mãe"
                ],
                "address": "551138839332"
            },
            {
                "type": "email",
                "tags": [
                    "Mãe"
                ],
                "address": "johndoemae1@gmail.com"
            },
            {
                "type": "email",
                "tags": [
                    "Aluno"
                ],
                "address": "johndoealuno1@gmail.com"
            }
        ],
        "class": [
            "Sala 1",
            "Sala 2",
            "Sala 3"
        ],
        "fullname": "John Doe 1",
        "eid": "2",
        "invisible": true,
        "see_all": false
    },
    {
        "addresses": [
            {
                "type": "email",
                "tags": [
                    "Responsável",
                    "Pai"
                ],
                "address": "johndoepai2@gmail.com"
            },
            {
                "type": "email",
                "tags": [
                    "Responsável",
                    "Pai"
                ],
                "address": "johndoepai3@gmail.com"
            },
            {
                "type": "phone",
                "tags": [
                    "Pai"
                ],
                "address": "5519985504400"
            },
            {
                "type": "phone",
                "tags": [
                    "Responsável",
                    "Mãe"
                ],
                "address": "551138839333"
            },
            {
                "type": "email",
                "tags": [
                    "Mãe"
                ],
                "address": "11 983340440"
            },
            {
                "type": "email",
                "tags": [
                    "Aluno"
                ],
                "address": ""
            }
        ],
        "class": [
            "Sala 4",
            "Sala 5",
            "Sala 6"
        ],
        "fullname": "John Doe 1",
        "eid": "2",
        "invisible": false,
        "see_all": true
    }

正如您所看到的,我们可以在内部包含一些数组中的字符串。 我尝试使用一些递归来做,但没有成功。

function mergeObjects(target, source){
    var item, tItem, o, idx;
    if (typeof source == 'undefined') {
      return source;
    } else if (typeof target == 'undefined') {
      return target;
    }

    for (var prop in source) {
        item = source[prop];
        //check if the first element is indeed an object.
        if (typeof item == 'object' && item !== null) {
            //if the first item is an array
          if (_.isArray(item) && item.length) {
              //dealing with array of primitives
              if (typeof item[0] != 'object') {
                  item.forEach(function(conteudo){
                      //push to the target all the elements;
                      target[prop].push(conteudo);
                  });
              }else{
                //dealing with array of objects;
                for(var attr in item){
                    idx = {};
                    tItem = target[attr]
                    mergeObjects(tItem,item);
                }
              }
          }//if its a normal object
          else {
           // deal with object
           mergeObjects(target[prop],item);
         }

        } else {
             // item is a primitive, just copy it over
             target[prop] = item;
           }
    }
    return target;
}

我期待这个:

  {
        "addresses": [
            {
                "type": "email",
                "tags": [
                    "Responsável",
                    "Pai"
                ],
                "address": "johndoepai2@gmail.com"
            },
            {
                "type": "email",
                "tags": [
                    "Responsável",
                    "Pai"
                ],
                "address": "johndoepai3@gmail.com"
            },
            {
                "type": "phone",
                "tags": [
                    "Pai"
                ],
                "address": "5519985504400"
            },
            {
                "type": "phone",
                "tags": [
                    "Responsável",
                    "Mãe"
                ],
                "address": "551138839333"
            },
            {
                "type": "email",
                "tags": [
                    "Mãe"
                ],
                "address": "11 983340440"
            },
            {
                "type": "email",
                "tags": [
                    "Aluno"
                ],
                "address": ""
            }
        ],
        "class": [
            "Sala 4",
            "Sala 5",
            "Sala 6",
            "Sala 1",
            "Sala 2",
            "Sala 3"
        ],
        "fullname": "John Doe 1",
        "eid": "2",
        "invisible": true,
        "see_all": false
    }

"fullname": "John Doe 1",
  "eid": "1234",
  "classes": [
    "Sala 1",
    "Sala 2",
    "Sala 3",
    "Sala 4",
    "Sala 5",
    "Sala 6"
  ],
  "addresses": [{
    "type": "phone",
    "tags": [
      "Responsável",
      "Mãe"
    ],
    "address": "551138839332"
  }, {
    "type": "email",
    "tags": [
      "Mãe"
    ],
    "address": "johndoemae1@gmail.com"
  }, {
    "type": "email",
    "tags": [
      "Aluno"
    ],
    "address": "johndoealuno1@gmail.com"
  }, {
    "type": "email",
    "tags": [
      "Responsável",
      "Pai"
    ],
    "address": "johndoepai2@gmail.com"
  }, {
    "type": "email",
    "tags": [
      "Responsável",
      "Pai"
    ],
    "address": "johndoepai3@gmail.com"
  }, {
    "type": "phone",
    "tags": [
      "Pai"
    ],
    "address": "5519985504400"
  }, {
    "type": "phone",
    "tags": [
      "Responsável",
      "Mãe"
    ],
    "address": "551138839333"
  }],
  "invisible": true,
  "see_all": true
}

但我得到的是,正如你所看到的,有些电子邮件元素丢失了。

{
    "addresses": [
        {
            "type": "email",
            "tags": [
                "Responsável",
                "Pai"
            ],
            "address": "johndoepai2@gmail.com"
        },
        {
            "type": "email",
            "tags": [
                "Responsável",
                "Pai"
            ],
            "address": "johndoepai3@gmail.com"
        },
        {
            "type": "phone",
            "tags": [
                "Pai"
            ],
            "address": "5519985504400"
        },
        {
            "type": "phone",
            "tags": [
                "Responsável",
                "Mãe"
            ],
            "address": "551138839333"
        },
        {
            "type": "email",
            "tags": [
                "Mãe"
            ],
            "address": "11 983340440"
        },
        {
            "type": "email",
            "tags": [
                "Aluno"
            ],
            "address": ""
        }
    ],
    "class": [
        "Sala 4",
        "Sala 5",
        "Sala 6",
        "Sala 1",
        "Sala 2",
        "Sala 3"
    ],
    "fullname": "John Doe 1",
    "eid": "2",
    "invisible": true,
    "see_all": false
}

元素顺序不是问题 我错过了递归树的哪一点?

1 个答案:

答案 0 :(得分:1)

简短回答:你必须先自己合并数组。或者你可以使用像Lodash's mergeWidth Ramda's R.mergeWith这样的好东西(参见下面的Ramda示例代码)。

你想要的东西就像本机的Object.assign(有限的浏览器支持,所以它必须是polyfilled)或者你的JS库有什么合并。

您遇到的问题是所有这些合并实现如何处理重复键。通常,密钥将设置为传入的最后一个值:

var thing1 = {
  someProperty: 'foo'
};

var thing2 = {
  someProperty: 'bar'
};

var result1 = Object.assign({}, thing1, thing2);
// -> {someProperty: 'bar'} (set to the last value passed in, in thing2)

var result2 = Object.assign({}, thing2, thing1);
// -> {someProperty: 'foo'} (again set to the last value passed in, in thing1)

// Make the Stackoverflow snippet display the output.
document.body.innerHTML += JSON.stringify(result1, null, 2);
document.body.innerHTML += '<br>' + JSON.stringify(result2, null, 2);

与您的示例以相同的方式工作,除了属性是一个更复杂的数组。它被设置为传入的最后一个数组:

var thing1 = {
  someList: [1, 2, 3]
};

var thing2 = {
  someList: [4, 5, 6]
};

var result = Object.assign({}, thing1, thing2);
// -> {someList: [4, 5, 6]}

// Make the Stackoverflow snippet display the output.
document.body.innerHTML = JSON.stringify(result, null, 2);

如果你使用像Ramda这样的东西,你可以合并并指定一个函数来控制键相等时的行为,就像你的情况一样。在这里,我们可以检查值是否为数组,然后连接,如果是这样。否则,返回最新值(如上所述):

var thing1 = {someList: [1, 2, 3]};
var thing2 = {someList: [4, 5, 6]};

var dupeMergeFn = function(a, b) {
  return (Array.isArray(a)) ? a.concat(b) : b;
};

var result = R.mergeWith(dupeMergeFn, thing1, thing2);

// Make the Stackoverflow snippet display the output.
document.body.innerHTML = JSON.stringify(result, null, 2);
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.19.1/ramda.min.js"></script>