Javascript嵌套数组转换

时间:2012-07-27 20:06:11

标签: javascript

我正试图了解Javascript数组函数。我有一个这样的嵌套数组,其中每一行都涵盖相同的时间段:

[{
    "category": "fruit",
    "variety": "apple",
    "data": [{
        "day": 1,
        "units": 2
    }, {"day": 2,
        "units": 4
    }]
},{
    "category": "fruit",
    "variety": "orange",
    "data": [{
        "day": 1,
        "units": 3
    }, {"day": 2,
        "units": 5
    }]
},{
    "category": "veg",
    "variety": "tomato",
    "data": [{
        "day": 1,
        "units": 4
    }, {"day": 2,
        "units": 2
    }]
}]

我想按类别按日分算单位,得到这样的数组:

[{
    "category": "fruit",
    "data": [{
        "day": 1,
        "units": 5
    }, {"day": 2,
        "units": 9
    }]
},{
    "category": "veg",
    "data": [{
        "day": 1,
        "units": 4
    }, {"day": 2,
        "units": 2
    }]
}]

我一直在通过长循环if语句解决这个问题,并对它进行一些哈希处理。你能看到解决这个问题的优雅方法吗?

非常感谢!

3 个答案:

答案 0 :(得分:2)

解决方案非常明显:遍历数组,并将数据存储在键值对中。然后,遍历has,并使用Array.prototype.map构造结果数组。最后,如果你想要一个格式良好的JSON字符串,请使用JSON.stringify(result, null, 4);,其中4是漂亮格式的间隔数。

演示:http://jsfiddle.net/jde6S/

var list = [ ... ];
var hash = {};
for (var i=0; i<list.length; i++) {
    var obj = list[i];

    // This part makes sure that hash looks like {fruit:[], veg: []}
    var hashObjCat = hash[obj.category];
    if (!hashObjCat) {
        hashObjCat = hash[obj.category] = {};
    }

    // This part populates the hash hashObjCat with day-unit pairs
    for (var j=0; j<obj.data.length; j++) {
        var data = obj.data[j];
        if (hashObjCat[data.day]) hashObjCat[data.day] += data.units;
        else hashObjCat[data.day] = data.units;
    }
}
// Now, we hash looks like {fruit: {1:5, 2:9} }
// Construct desired object
var result = Object.keys(hash).map(function(category) {
    // Initial object
    var obj = {category: category, data:[]};
    var dayData = Object.keys(hash[category]);
    // This part adds  day+units dicts to the data array
    for (var i=0; i<dayData.length; i++) {
        var day = dayData[i];
        var units = hash[category][day];
        obj.data.push({day: day, units: units});
    }
    return obj;
});
// Test:
console.log(JSON.stringify(result, null, 4));

答案 1 :(得分:2)

reduce数组到一个对象(参见@ RobW关于如何用循环做的回答):

var data = [...] // your input 

// Iterate the data with reduce...
var sumsbycategory = data.reduce(function(map, fruit) {
    var cat = fruit.category;
    // set an property to an object, iterating the days array...
    map[cat] = fruit.data.reduce(function(sums, day) {
        var d = day.day;
        // set or update the units for this day
        sums[d] = (sums[d] || 0) + day.units;
        return sums; // into the next iteration
    }, map[cat] || {}) // ...passing in the already existing map for this cat or a new one
    return map; // into the next iteration
}, {}); // ...passing in an empty object

现在我们有以下格式:

{"fruit":{"1":5,"2":9},"veg":{"1":4,"2":2}}

...我觉得它更容易处理,但是让我们构建你的数组:

var result = []; // init array
for (var cat in sumsbycategory) { // loop over categories
    var data = []; // init array
    // add category object:
    result.push({category:cat, data:data});
    for (var day in sumsbycategory[cat]) // loop over days in category
         // add day object
         data.push({day:day, units:sumsbycategory[cat][day]});
}

但是,等等!一个对象没有顺序,day2可能发生在结果数组days1之前(可能会破坏你的应用程序?)所以,你可以在{{3}上使用map该对象之前也可能是keys,以一个看起来很干净的表达式生成数组:

var result = Object.keys(sumsbycategory).map(function(cat) {
    return {
        category: cat,
        data: Object.keys(sumsbycategory[cat])
         .sort(function numbercompare(a,b){ return a-b; })
         .map(function(day) {
            return {
                day: day,
                units: sumsbycategory[cat][day]
            };
        })
    };
});

结果:

[{
  "category": "fruit",
  "data": [{"day":"1","units":5},{"day":"2","units":9}]
 },{
  "category": "veg",
  "data": [{"day":"1","units":4},{"day":"2","units":2}]
}]

sorted

答案 2 :(得分:0)

如果您愿意获取一些外部代码并使用它来重新索引您的结构,您可能会做一些事情。我知道旧的dojo数据api是一个混乱的工作,但可以允许像你似乎要问的东西。

就个人而言,我坚持使用循环,只需保持变量名称的可读性。还要记住,对象文字可以作为数组/哈希语法x [y]或点语法x.y

来处理。