1

我试图了解 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 语句来解决这个问题,并对其进行一些散列。你能看到一个优雅的方法来解决这个问题吗?

非常感谢!

4

3 回答 3

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));
于 2012-07-27T20:29:52.943 回答
2

将数组减少为一个对象(有关如何使用循环执行此操作,请参阅@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(这可能会破坏您的应用程序?)因此,您可以在该对象的键上使用映射,该键也可以在之前排序,以生成一个数组干净利落的表达:

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}]
}]

在 jsfiddle.net 上的演示

于 2012-07-27T20:37:57.123 回答
0

如果您愿意获取一些外部代码并使用它来重新索引您的结构,您可能会做一些事情。我知道旧的 dojo 数据 api 使用起来很混乱,但可以允许您似乎在问什么。

就我个人而言,我会坚持使用循环,只是保持你的变量名可读。还要记住,对象字面量可以用数组/哈希语法 x[y] 或点语法 xy 来寻址

于 2012-07-27T20:12:07.400 回答