Linq cevabı ilginç olmasına rağmen, aynı zamanda oldukça ağırdır. Benim yaklaşımım biraz farklı:
var DataGrouper = (function() {
var has = function(obj, target) {
return _.any(obj, function(value) {
return _.isEqual(value, target);
});
};
var keys = function(data, names) {
return _.reduce(data, function(memo, item) {
var key = _.pick(item, names);
if (!has(memo, key)) {
memo.push(key);
}
return memo;
}, []);
};
var group = function(data, names) {
var stems = keys(data, names);
return _.map(stems, function(stem) {
return {
key: stem,
vals:_.map(_.where(data, stem), function(item) {
return _.omit(item, names);
})
};
});
};
group.register = function(name, converter) {
return group[name] = function(data, names) {
return _.map(group(data, names), converter);
};
};
return group;
}());
DataGrouper.register("sum", function(item) {
return _.extend({}, item.key, {Value: _.reduce(item.vals, function(memo, node) {
return memo + Number(node.Value);
}, 0)});
});
Görebiliyorsun JSBin üzerinde eylem .
Undercore'da bunu yapan hiçbir şey görmedim has, ancak onu kaçırıyor olabilirim. Oldukça aynı _.contains, ancak karşılaştırmalar _.isEqualyerine kullanır ===. Bunun dışında, genel olmaya çalışılsa da, bunun geri kalanı probleme özgüdür.
Şimdi DataGrouper.sum(data, ["Phase"])geri dönüyor
[
{Phase: "Phase 1", Value: 50},
{Phase: "Phase 2", Value: 130}
]
Ve DataGrouper.sum(data, ["Phase", "Step"])geri dönüyor
[
{Phase: "Phase 1", Step: "Step 1", Value: 15},
{Phase: "Phase 1", Step: "Step 2", Value: 35},
{Phase: "Phase 2", Step: "Step 1", Value: 55},
{Phase: "Phase 2", Step: "Step 2", Value: 75}
]
Ancak sumburada sadece bir potansiyel işlev var. Başkalarını istediğiniz şekilde kaydedebilirsiniz:
DataGrouper.register("max", function(item) {
return _.extend({}, item.key, {Max: _.reduce(item.vals, function(memo, node) {
return Math.max(memo, Number(node.Value));
}, Number.NEGATIVE_INFINITY)});
});
ve şimdi DataGrouper.max(data, ["Phase", "Step"])geri dönecek
[
{Phase: "Phase 1", Step: "Step 1", Max: 10},
{Phase: "Phase 1", Step: "Step 2", Max: 20},
{Phase: "Phase 2", Step: "Step 1", Max: 30},
{Phase: "Phase 2", Step: "Step 2", Max: 40}
]
veya bunu kaydettiyseniz:
DataGrouper.register("tasks", function(item) {
return _.extend({}, item.key, {Tasks: _.map(item.vals, function(item) {
return item.Task + " (" + item.Value + ")";
}).join(", ")});
});
o zaman aramak DataGrouper.tasks(data, ["Phase", "Step"])seni alacak
[
{Phase: "Phase 1", Step: "Step 1", Tasks: "Task 1 (5), Task 2 (10)"},
{Phase: "Phase 1", Step: "Step 2", Tasks: "Task 1 (15), Task 2 (20)"},
{Phase: "Phase 2", Step: "Step 1", Tasks: "Task 1 (25), Task 2 (30)"},
{Phase: "Phase 2", Step: "Step 2", Tasks: "Task 1 (35), Task 2 (40)"}
]
DataGrouperkendisi bir işlevdir. Verileriniz ve gruplandırmak istediğiniz özelliklerin bir listesi ile arayabilirsiniz. Öğeleri iki özelliğe sahip nesne olan bir dizi döndürür: keygruplandırılmış özelliklerin toplanması vals, anahtarda olmayan kalan özellikleri içeren bir nesne dizisidir. Örneğin, DataGrouper(data, ["Phase", "Step"])verim:
[
{
"key": {Phase: "Phase 1", Step: "Step 1"},
"vals": [
{Task: "Task 1", Value: "5"},
{Task: "Task 2", Value: "10"}
]
},
{
"key": {Phase: "Phase 1", Step: "Step 2"},
"vals": [
{Task: "Task 1", Value: "15"},
{Task: "Task 2", Value: "20"}
]
},
{
"key": {Phase: "Phase 2", Step: "Step 1"},
"vals": [
{Task: "Task 1", Value: "25"},
{Task: "Task 2", Value: "30"}
]
},
{
"key": {Phase: "Phase 2", Step: "Step 2"},
"vals": [
{Task: "Task 1", Value: "35"},
{Task: "Task 2", Value: "40"}
]
}
]
DataGrouper.registerbir işlevi kabul eder ve ilk verileri ve gruplanacak özellikleri kabul eden yeni bir işlev oluşturur. Bu yeni işlev daha sonra çıkış biçimini yukarıdaki gibi alır ve işlevinizi sırayla her birine karşı çalıştırır ve yeni bir dizi döndürür. Oluşturulan işlev, DataGroupersağladığınız bir ada göre bir özellik olarak depolanır ve yalnızca yerel bir başvuru istiyorsanız döndürülür.
Bu çok fazla açıklama. Kod oldukça basit, umarım!