分组和合并javascript对象

时间:2015-06-27 10:25:07

标签: javascript lodash

我有一系列javascript对象,我想合并和分组。 这就是我输入的内容:

var input = [ 
  { // 0
    A: { i: 0, j: 1 },
    'A.k': { ki: 10, kj: 11 },
    'A.k.l': { li: 20, lj: 21 }
  },
  { // 1
    A: { i: 0, j: 1 },
    'A.k': { ki: 10, kj: 11 },
    'A.k.l': { li: 22, lj: 23 }
  },
  { // 2
    A: { i: 0, j: 1 },
    'A.k': { ki: 12, kj: 13 },
    'A.k.l': { li: 24, lj: 25 }
  },
  { // 3
    A: { i: 0, j: 1 },
    'A.k': { ki: 12, kj: 13 },
    'A.k.l': { li: 26, lj: 27 }
  },
  { // 4
    A: { i: 2, j: 3 },
    'A.k': { ki: 14, kj: 15 },
    'A.k.l': { li: 28, lj: 29 }
  },
  { // 5
    A: { i: 2, j: 3 },
    'A.k': { ki: 14, kj: 15 },
    'A.k.l': { li: 30, lj: 31 }
  },
  { // 6
    A: { i: 2, j: 3 },
    'A.k': { ki: 16, kj: 17 },
    'A.k.l': { li: 32, lj: 33 }
  },
  { // 7
    A: { i: 2, j: 3 },
    'A.k': { ki: 16, kj: 17 },
    'A.k.l': { li: 34, lj: 35 }
  }
];

我试图把它变成:

var output = [ 
    { i: 0, j: 1, k: [ 
        { ki: 10, kj: 11, l: [ { li: 20, lj: 21 }, { li: 22, lj: 23 } ] },
        { ki: 12, kj: 13, l: [ { li: 24, lj: 25 }, { li: 26, lj: 27 } ] } 
    ]
    },
    { i: 2, j: 3, k: [ 
        { ki: 14, kj: 15, l: [ { li: 28, lj: 29 }, { li: 30, lj: 31 } ] },
        { ki: 16, kj: 17, l: [ { li: 32, lj: 33 }, { li: 34, lj: 35 } ] } 
    ]
    }
];

我使用lodash,现在我的第一个想法是:

  • 1)合并每个对象属性(使用_.set)
  • 2)通过使用一种标识符比较值来合并每个数组项,但在处理深度值时会变得复杂

即使没有解决方案,也欢迎任何帮助。

2 个答案:

答案 0 :(得分:0)

首先需要转换input数组,因为您在所需的输出中没有A proprety而某些项目是嵌套的

 var intermediate = input.map(function (item) {
  //restructure so that 'A.k' has name 'k' and is subitem, 
  //and 'A.k.l' is subitem of 'k' with name 'l'
    return {
      i: item.A.i,
      j: item.A.j,
      k: [{
        kj: item['A.k'].kj,
        ki: item['A.k'].ki,
        l: [{
          lj: item['A.k.l'].lj,
          li: item['A.k.l'].li,
        }]
      }]
    }
  });

然后我们定义一个按给定键合并的函数(对象中的这些键应该是基本类型)。将重用此函数来合并多个级别

  function merge(collection, keys) {
    var result = _.groupBy(collection, function (item) {
 // return a hash to group items. It won't be used to construct objects, just for grouping
 // it must be a primitive type. will use string consisting of values
 // dilimiter must be non-number and not empty to avoid false match of 1, 11 and 11, 1
      return keys.map(function (key) {
        return item[key]
      }).join('-');
    })
    result = _.pairs(result)
      .map(function (group) {
        var list = group[1];
        //list has items with fields names in [keys] equal
        //merge all items with concatenatation of arrays
        var res = _.reduce(list, function (a, b) {
          return _.merge(a, b, function (prop1, prop2) {
            if (_.isArray(prop1)) {
              return prop1.concat(prop2);
            }
          });
        });
        return res;
      });
    return result;
  }

  //merge top level
  var output = merge(intermediate, ['i', 'j']);
  _.map(output, function (item) {
    //merge children - in 'k'
    item.k = merge(item.k, ['ki', 'kj']);
  });

action;

中查看

答案 1 :(得分:0)

没有_的解决方案

var input = [{ // 0
      'A': { i: 0, j: 1 },
      'A.k': { ki: 10, kj: 11 },
      'A.k.l': { li: 20, lj: 21 }
  }, { // 1
      A: { i: 0, j: 1 },
      'A.k': { ki: 10, kj: 11 },
      'A.k.l': { li: 22, lj: 23 }
  }, { // 2
      A: { i: 0, j: 1 },
      'A.k': { ki: 12, kj: 13 },
      'A.k.l': { li: 24, lj: 25 }
  }, { // 3
      A: { i: 0, j: 1 },
      'A.k': { ki: 12, kj: 13 },
      'A.k.l': { li: 26, lj: 27 }
  }, { // 4
      A: { i: 2, j: 3 },
      'A.k': { ki: 14, kj: 15 },
      'A.k.l': { li: 28, lj: 29 }
  }, { // 5
      A: { i: 2, j: 3 },
      'A.k': { ki: 14, kj: 15 },
      'A.k.l': { li: 30, lj: 31 }
  }, { // 6
      A: { i: 2, j: 3 },
      'A.k': { ki: 16, kj: 17 },
      'A.k.l': { li: 32, lj: 33 }
  }, { // 7
      A: { i: 2, j: 3 },
      'A.k': { ki: 16, kj: 17 },
      'A.k.l': { li: 34, lj: 35 }
  }
];
var output = [];

function findIndex(a, o) {
    var index;
    a.some(function (el, n) {
        var found = true, i;
        for (i in o) {
            found = found && el[i] === o[i];
        }
        return found ? (index = n, true) : false;
    });
    return index;
};

input.forEach(function (el) {
    var i,
        o = {},
        k = {},
        l = {},
        index = findIndex(output, { i: el.A.i, j: el.A.j });
    if (isFinite(index)) {
        o = output[index];
    } else {
        o.i = el.A.i;
        o.j = el.A.j;
        o.k = [];
        output.push(o);
    }
    index = findIndex(o.k, { ki: el['A.k'].ki, kj: el['A.k'].kj });
    if (isFinite(index)) {
        k = o.k[index];
    } else {
        k.ki = el['A.k'].ki;
        k.kj = el['A.k'].kj;
        k.l = [];
        o.k.push(k);
    }
    for (i in el['A.k.l']) {
        l[i] = el['A.k.l'][i];
    }
    k.l.push(l);
});

out(JSON.stringify(output, null, 4), true);

function out(s, pre) {
    var descriptionNode = document.createElement('div');
    if (pre) {
        var preNode = document.createElement('pre');
        preNode.innerHTML = s + '<br>';
        descriptionNode.appendChild(preNode);
    } else {
        descriptionNode.innerHTML = s + '<br>';
    }
    document.getElementById('out').appendChild(descriptionNode);
}
<div id="out"></div>