嵌套或不平坦的阵列

时间:2013-10-07 08:12:15

标签: javascript arrays underscore.js

我有一个看起来像这样的对象数组。

var arr = [{'id':21 ,'name' : 'name 1' ,'vehiclename' : 'vehicle 1' ,'parentid' : 21},
           {'id':21 ,'name' : 'name 1' ,'vehiclename' : 'vehicle 2' ,'parentid' : 21},
           {'id':22 ,'name' : 'name 2' ,'vehiclename' : 'vehicle 1' ,'parentid' : 22},
           {'id':22 ,'name' : 'name 2' ,'vehiclename' : 'vehicle 2' ,'parentid' : 22}]

我想对数组进行取消或分组,现在看起来像这样。

var arr = [{'id':21,
             name: 'name 1'
             vehicles : [{'vehiclename':'vehicle 1','parentid':21},
                         {'vehiclename':'vehicle 2','parentid':21}] },
           {'id':22,
             name: 'name 2'
             vehicles : [{'vehiclename':'vehicle 1','parentid':22},
                         {'vehiclename':'vehicle 2','parentid':22}] }
           }]

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:5)

对于那些好奇的人,这是一个强硬的解决方案:

grouped = _.map(_.groupBy(arr, 'id'), function(b) {
    return _.extend(_.pick(b[0], 'id', 'name'), {
        vehicles: _.map(b, function(elem) {
            return _.pick(elem, 'vehiclename', 'parentid')
        })
    });
});

http://jsfiddle.net/bgAzH/1/

答案 1 :(得分:2)

您已使用“underscore.js”标记了您的问题,我确信下划线会让这更容易,但由于我不熟悉它,因此这是一个使用Vanilla JS的解决方案:

var working = {},
    output = [],
    id,
    i;

for (i = 0; i < arr.length; i++) {
    id = arr[i].id;
    if (!(id in working))
        working[id] = {id : id, name : arr[i].name, vehicles : []};

    working[id].vehicles.push({vehiclename : arr[i].vehiclename,
                               parentid : arr[i].parentid});
}

for (i in working)
    output.push(working[i]);

// output is now an array of objects in your desired format

我没有直接生成新的output数组,而是使用working对象开始,因此很容易测试是否还看到了给定的id。然后我将working对象中的每个项目放入一个实际的数组中。

答案 2 :(得分:0)

我试图让它更具可配置性,看起来不像给定的解决方案那么好但是决定一个属性应该是最终对象中的数组,还允许配置键映射到某个键在最后一个对象中,这可能对更通用的情况有用。

var _ = require("underscore")

var res = []

var arr = [
  {'id':21 ,'name' : 'name1' ,'vehiclename' : 'vehicle1' ,'parentid' : 21},
  {'id':21 ,'name' : 'name1' ,'vehiclename' : 'vehicle2' ,'parentid' : 21},
  {'id':22 ,'name' : 'name2' ,'vehiclename' : 'vehicle1' ,'parentid' : 22},
  {'id':22 ,'name' : 'name2' ,'vehiclename' : 'vehicle2' ,'parentid' : 22},
]

var connected = [{
  name: "vehicles",
  props: [ "vehiclename", "parentid" ]
}]

arr.forEach(function(e) {
  var obj = _.findWhere(res, { id: e.id })
  if(!obj) {
    obj = { id: e.id }
    res.push(obj)
  }
  var props = _.omit(e, "id");
  connected.forEach(function(cp) {
    props = _.omit.apply(this, [props, cp.props])
  })
  for(p in props) {
    copyPropToObj(props[p], p, obj);
  }
  connected.forEach(function(cp) {
    copyPropToObj(_.pick.apply(this, [e, cp.props]), cp.name, obj)
  })
})

function copyPropToObj(prop, propName, obj) {
  var oProp = _.clone(obj[propName])
  if(oProp && (prop === oProp)) {
    return
  } else if(oProp) {
    // we already have a value, need to move to an array
    obj[propName] = []
    obj[propName].push(prop)
    obj[propName].push(oProp)
  } else {
    // we don't have it set yet so just copy over
    obj[propName] = prop
  }
}

res.forEach(function(e) {
  console.log(e)
})