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

配列をオブジェクトに減らします(ループでそれを行う方法については@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]});
}

ちょっと待って!オブジェクトには順序がなく、結果の配列でday2days1に来る可能性があります (アプリケーションが壊れる可能性がありますか?) そのため、前に並べ替えることができるそのオブジェクトのキーでmapを使用して、配列を 1 つに生成できます。すっきりとした表情:

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 に答える
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 に答える
0

いくつかの外部コードを取得し、それを使用して本質的に構造の再インデックスを作成する場合は、おそらく何かを行うことができます。古い道場のデータ API は扱いにくいものでしたが、あなたが求めているようなものを許可することができました。

個人的には、変数名を読みやすくしておいてください。また、オブジェクト リテラルは、配列/ハッシュ構文 x[y] またはドット構文 xy としてアドレス指定できることも覚えておいてください。

于 2012-07-27T20:12:07.400 に答える