我正试图了解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语句解决这个问题,并对它进行一些哈希处理。你能看到解决这个问题的优雅方法吗?
非常感谢!
答案 0 :(得分:2)
解决方案非常明显:遍历数组,并将数据存储在键值对中。然后,遍历has,并使用Array.prototype.map
构造结果数组。最后,如果你想要一个格式良好的JSON字符串,请使用JSON.stringify(result, null, 4);
,其中4
是漂亮格式的间隔数。
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
来处理。