根据多个键合并两个数组中的对象

时间:2015-12-04 07:31:27

标签: javascript

下面有两个数组,我想根据两个常用键(“iso3”和“year”)进行合并。每个对象必须具有共同的两个才能合并。数组长度不一样。

array1 = [{
  "id":24006,
  "iso3":"AFG",
  "country":"Afghanistan",
  "year":2014,
  "value":29.78
},
{
  "id":138806,
  "iso3":"ALB",
  "country":"Albania",
  "year":2013,
  "value":0.6341109715
},
{
  "id":44206,
  "iso3":"DZA",
  "country":"Algeria",
  "year":2014,
  "value":39.928947
}]

array2 = [{
  "indicator_id":21806,
  "footnote_id":64811,
  "iso3":"AFG",
  "year":2014
},
{
  "indicator_id":23806,
  "footnote_id":15711,
  "iso3":"AFG",
  "year":2013
},
{
  "indicator_id":123406,
  "footnote_id":15711,
  "iso3":"ALB",
  "year":2013
},
{
  "indicator_id":101606,
  "footnote_id":48911,
  "iso3":"DZA",
  "year":2013
}];

I saw this answer,但只根据一个公共密钥合并数组。我尝试使用该代码,但我没有得到任何结果。任何帮助表示赞赏!

4 个答案:

答案 0 :(得分:2)

另一种利用sort()reduce()的方法。

JSFiddle example

代码:

/* Merges two objects into one. You might add some custom logic here,
   if you need to handle some more complex merges, i.e. if the same
   key appears in merged objects in both arrays */
var merge = function(o1, o2) {
  var result = {};
  for (var a in o1) { result[a] = o1[a]; }
  for (var a in o2) { result[a] = o2[a]; }
  return result;
}

/* Returns 0 if two objects are equal, -1 if first one is 'lower',
   and 1 if it's 'larger'. It's used to sort the arrays. Objects are
   compared using iso3 and year properties only. */
var compareByIsoAndYear = function (o1, o2) {
  if (o1.iso3 === o2.iso3 && o1.year === o2.year) return 0
  else if (o1.year > o2.year) return 1
  else if (o1.year < o2.year) return -1
  else if (o1.iso3 > o2.iso3) return 1;
}

/* Used in reduce */
var mergeTwoObjects = function(initial, current) {
  if (initial.length > 0) {
    var last = initial[initial.length-1];
    if (compareByIsoAndYear(last, current) === 0) {
      initial[initial.length-1] = merge(last, current);
      return initial;
    }
  }
  initial.push(current);
  return initial;
}

/* Take both arrays and concatenate them into one. Then sort them,
   to make sure that objects with the same year and iso3 would appear
   next to each other, and then merge them if needed */
var result = array1.concat(array2)
                   .sort(compareByIsoAndYear)
                   .reduce(mergeTwoObjects, []);

结果:

[{
  "indicator_id": 23806,      /* Found in array2 only, not merged */
  "footnote_id": 15711,
  "iso3": "AFG",
  "year": 2013
}, {
  "id": 138806,               /* This one has been merged */
  "iso3": "ALB",
  "country": "Albania",
  "year": 2013,
  "value": 0.6341109715,
  "indicator_id": 123406,
  "footnote_id": 15711
}, {           
  "indicator_id": 101606,     /* Found in array2 only, not merged */
  "footnote_id": 48911,
  "iso3": "DZA",
  "year": 2013
}, {
  "id": 24006,                /* This one has been merged */
  "iso3": "AFG",
  "country": "Afghanistan",
  "year": 2014,
  "value": 29.78,
  "indicator_id": 21806,
  "footnote_id": 64811
}, {
  "id": 44206,                /* Found in array1 only, not merged */
  "iso3": "DZA",
  "country": "Algeria",
  "year": 2014,
  "value": 39.928947
}]

答案 1 :(得分:0)

您需要做的是延长您选择的答案中提供的加入条件。像这样:

var combined = [];
function findSecond(iso3, year, second){
    for (var i = 0; i < second.length; i += 1){
    //Adding the second condition
        if (second[i].iso3 === iso3 && second[i].year ===  year ) {
            return second[i];
        }
    }
    return null;
}

while (el = array1.pop()){
    var getSec = findSecond(el.iso3, el.year, array2);
    if (getSec){
        for (var l in getSec){
            if (!(l in el)) {
                el[l] = getSec[l];
            }
        }
        combined.push(el);
    }
}

答案 2 :(得分:0)

此方法首先根据键创建合并对象的字典(或映射)。它使用jQuery $ .extend来合并各个对象(其他实用程序库可能会提供合并对象的方法)

在生成字典后,它会转换回数组并按单个对象键进行过滤,以生成类似结果的内连接。如果您在外部联接之后,只需删除过滤器。

var array1 = [{
  "id":24006,
  "iso3":"AFG",
  "country":"Afghanistan",
  "year":2014,
  "value":29.78
},
{
  "id":138806,
  "iso3":"ALB",
  "country":"Albania",
  "year":2013,
  "value":0.6341109715
},
{
  "id":44206,
  "iso3":"DZA",
  "country":"Algeria",
  "year":2014,
  "value":39.928947
}]

var array2 = [{
  "indicator_id":21806,
  "footnote_id":64811,
  "iso3":"AFG",
  "year":2014
},
{
  "indicator_id":23806,
  "footnote_id":15711,
  "iso3":"AFG",
  "year":2013
},
{
  "indicator_id":123406,
  "footnote_id":15711,
  "iso3":"ALB",
  "year":2013
},
{
  "indicator_id":101606,
  "footnote_id":48911,
  "iso3":"DZA",
  "year":2013
}];

// merge by key where possible
var dict = array1.concat(array2).reduce(function (dict, val) {
    // Use the two values we want to join on as a key
      var key = val.iso3 + val.year;

    // Lookup existing object with same key, default to
    // empty object if one does not exist
    var existing = dict[key] || {};

    // Merge two objects
    dict[key] = $.extend(existing, val);

    return dict; 
}, {});

var joined = Object.keys(dict).map(function (key) {
  // pull the dictionary values back out into an array
  return dict[key];
}).filter(function (obj) {
  // this is making it work like an inner out, an outer join can be
  // done by removing the filter
  return (typeof obj.indicator_id !== "undefined") && (typeof obj.country !== "undefined");
});

JS Fiddle(输出记录到控制台:http://jsfiddle.net/9v47zLy6/

答案 3 :(得分:0)

此解决方案具有一个用于收集项目的对象,然后呈现所需的数组。

&#13;
&#13;
var array1 = [{ "id": 24006, "iso3": "AFG", "country": "Afghanistan", "year": 2014, "value": 29.78 }, { "id": 138806, "iso3": "ALB", "country": "Albania", "year": 2013, "value": 0.6341109715 }, { "id": 44206, "iso3": "DZA", "country": "Algeria", "year": 2014, "value": 39.928947 }],
    array2 = [{ "indicator_id": 21806, "footnote_id": 64811, "iso3": "AFG", "year": 2014 }, { "indicator_id": 23806, "footnote_id": 15711, "iso3": "AFG", "year": 2013 }, { "indicator_id": 123406, "footnote_id": 15711, "iso3": "ALB", "year": 2013 }, { "indicator_id": 101606, "footnote_id": 48911, "iso3": "DZA", "year": 2013 }];

function merge(array1, array2) {

    function makeObj(a) {
        obj[a.iso3] = obj[a.iso3] || {};
        obj[a.iso3][a.year] = obj[a.iso3][a.year] || {};
        Object.keys(a).forEach(function (k) {
            obj[a.iso3][a.year][k] = a[k];
        });
    }
    var array = [],
        obj = {};

    array1.forEach(makeObj);
    array2.forEach(makeObj);
    Object.keys(obj).forEach(function (k) {
        Object.keys(obj[k]).forEach(function (kk) {
            array.push(obj[k][kk]);
        });
    });
    return array;
}

document.write('<pre>' + JSON.stringify(merge(array1, array2), 0, 4) + '</pre>');
&#13;
&#13;
&#13;