我编写了这个函数,用一个或多个属性对数组进行分组:
var groupBy = function (fields, data) {
var groups = {};
for (var i = 0; i < data.length; i++) {
var item = data[i];
var container = groups;
for (var j = 0; j < fields.length; j++) {
var groupField = fields[j];
var groupName = item[groupField];
if (!container[groupName]) {
container[groupName] = j < fields.length - 1 ? {} : [];
}
container = container[groupName];
}
container.push(item);
}
return groups;
};
例如,如果我使用此输入
var animals = [
{type: "cat", name: "Max"},
{type: "dog", name: "Charlie"},
{type: "cat", name: "Zoe"},
{type: "dog", name: "Abby"},
{type: "cat", name: "Molly"}
];
var groupedAnimals = groupBy(["type"], animals);
我得到了这个输出:
{
"cat": [
{
"type": "cat",
"name": "Max"
},
{
"type": "cat",
"name": "Zoe"
},
{
"type": "cat",
"name": "Molly"
}
],
"dog": [
{
"type": "dog",
"name": "Charlie"
},
{
"type": "dog",
"name": "Abby"
}
]
}
到目前为止一切都还可以......问题是我需要键来反映原始输入数组的顺序。因此,如果第一项是猫,我迭代组键,我需要第一个键是猫。由于JS中的对象明确没有排序,我无法保证正确的顺序。我怎样才能做到这一点?
编辑:
我想结果必须是这样的:
groupBy(["type", "name"], animals)
应该产生:
[
{
"group": "cat",
"items": [
{
"group": "max",
"items": [
{
"type": "cat",
"name": "Max"
}
]
},
{
"group": "Zoe",
"items": [
{
"type": "cat",
"name": "Zoe"
}
]
},
{
"group": "Molly",
"items": [
{
"type": "cat",
"name": "Molly"
}
]
}
]
},
{
"group": "dog",
"items": [
{
"group": "Charlie",
"items": [
{
"type": "dog",
"name": "Charlie"
}
]
},
{
"group": "Abby",
"items": [
{
"type": "dog",
"name": "Abby"
}
]
}
]
}
]
答案 0 :(得分:1)
您可以将结果数据结构更改为数组数组,以便保持顺序。
var animals = [
{type: "cat", name: "Max"},
{type: "dog", name: "Charlie"},
{type: "cat", name: "Zoe"},
{type: "dog", name: "Abby"},
{type: "cat", name: "Molly"}
];
var result = []
animals.forEach(function(e) {
if(!this[e.type]) {
this[e.type] = [e.type, []]
result.push(this[e.type])
}
this[e.type][1].push(e)
}, {})
console.log(result)
&#13;
要按多个字段分组,您可以将数组作为第一个参数传递给函数
var animals = [
{type: "cat", name: "Max", i: 2},
{type: "dog", name: "Charlie", i: 2},
{type: "cat", name: "Zoe", i: 2},
{type: "dog", name: "Abby", i: 1},
{type: "cat", name: "Molly", i: 2}
];
function groupBy(fields, data) {
var result = []
data.forEach(function(e) {
var group = fields.map(a => e[a]).join('-')
if (!this[group]) {
this[group] = [group, []]
result.push(this[group])
}
this[group][1].push(e)
}, {})
return result
}
console.log(groupBy(['type', 'i'], animals))
&#13;
答案 1 :(得分:1)
您可以稍微更改一下您的功能,以便在每个组级别添加一个特殊属性,按照应该迭代的顺序列出键:
var groupBy = function (fields, data) {
var groups = { _keys: [] };
// ^^^^^^^^^
for (var i = 0; i < data.length; i++) {
var item = data[i];
var container = groups;
for (var j = 0; j < fields.length; j++) {
var groupField = fields[j];
var groupName = item[groupField];
if (!container[groupName]) {
container[groupName] = j < fields.length - 1 ? { _keys: [] } : [];
// ^^^^^^^^^
container._keys.push(groupName);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
container = container[groupName];
}
container.push(item);
}
return groups;
};
var animals = [
{type: "cat", name: "Max"},
{type: "dog", name: "Charlie"},
{type: "cat", name: "Zoe"},
{type: "dog", name: "Abby"},
{type: "cat", name: "Molly"}
];
var groupedAnimals = groupBy(["type"], animals);
console.log(groupedAnimals);
// Output types in order:
console.log('output types in fixed order:');
groupedAnimals._keys.forEach(function (key, i) {
console.log(i, key, groupedAnimals[key]);
});
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
答案 2 :(得分:1)
您可以使用完全动态的功能对各种键和深度进行分组。
此提案适用于每个级别的哈希表和数组。
function groupBy(keys, array) {
var result = [];
array.forEach(function (a) {
keys.reduce(function (r, k) {
if (!r[a[k]]) {
r[a[k]] = { _: [] };
r._.push({ group: a[k], items: r[a[k]]._ });
}
return r[a[k]];
}, this)._.push(a);
}, { _: result });
return result;
}
var animals = [{ type: "cat", name: "Max" }, { type: "dog", name: "Charlie" }, { type: "cat", name: "Zoe" }, { type: "dog", name: "Abby" }, { type: "cat", name: "Molly" }];
console.log(groupBy(["type", "name"], animals));
console.log(groupBy(["type"], animals));
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;