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 _.isEqual
yerine 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 sum
burada 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)"}
]
DataGrouper
kendisi 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: key
gruplandı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.register
bir 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, DataGrouper
sağ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!