我有一个嵌套的对象数组,如下所示。
[
{
"region": null,
"country": null,
"territory": "Worldwide",
"territoryCode": "ALL",
"t2": null,
"t3": null,
"t4": null,
"t5": null,
"t6": null,
"t7": null,
"localLanguage": {
"territoryId": 1,
"localLanguageName": "N/A",
"localLanguageCode": null
}
},
{
"region": "Africa",
"country": "Madagascar",
"territory": null,
"territoryCode": "MG",
"t2": "AFR",
"t3": "MG",
"t4": null,
"t5": null,
"t6": null,
"t7": null,
"localLanguage": {
"territoryId": 30,
"localLanguageName": "Malagasy, French",
"localLanguageCode": "MLG, FRE"
}
},
{
"region": "Africa",
"country": null,
"territory": null,
"territoryCode": "AFR",
"t2": "AFR",
"t3": null,
"t4": null,
"t5": null,
"t6": null,
"t7": null,
"localLanguage": {
"territoryId": 2,
"localLanguageName": "N/A",
"localLanguageCode": null
}
},
{
"region": "Africa",
"country": "Morocco (incl. Western Sahara)",
"territory": null,
"territoryCode": "MA",
"t2": "AFR",
"t3": "MA",
"t4": null,
"t5": null,
"t6": null,
"t7": null,
"localLanguage": {
"territoryId": 35,
"localLanguageName": "Arabic, French",
"localLanguageCode": "ARA, FRE"
}
},
{
"region": "Africa",
"country": "Morocco (incl. Western Sahara)",
"territory": "Morocco (excl. Western Sahara)",
"territoryCode": "MAXEH",
"t2": "AFR",
"t3": "MA",
"t4": "MAXEH",
"t5": null,
"t6": null,
"t7": null,
"localLanguage": {
"territoryId": 36,
"localLanguageName": "Arabic, French",
"localLanguageCode": "ARA, FRE"
}
},
{
"region": "Africa",
"country": "Morocco (incl. Western Sahara)",
"territory": "Western Sahara",
"territoryCode": "EH",
"t2": "AFR",
"t3": "MA",
"t4": "EH",
"t5": null,
"t6": null,
"t7": null,
"localLanguage": {
"territoryId": 37,
"localLanguageName": "Arabic, French",
"localLanguageCode": "ARA, FRE"
}
}
]
我希望根据独特的地区、国家/地区、t2-t7 组合对整个数据对象进行分组,并获得如下所示的输出
[{
"region": "Africa",
"country": [{
"desc": "Madagascar",
"t2": [{
"id": "AFR",
"localLanguageName": "Malagasy, French",
"localLanguageCode": "MLG, FRE"
"t3": [{
"id": "MG"
}]
}]
},
{
"desc": "Morocco (incl. Western Sahara)",
"subTerritory": [{
"t2": "AFR",
"t3": [{
"id": "MA",
"localLanguageName": "Arabic, French",
"localLanguageCode": "ARA, FRE"
"t4": [{
"id": "MAXEH",
"localLanguageName": "Arabic, French",
"localLanguageCode": "ARA, FRE"
"t5": [{
"id": ""
.
.
.
}]
},
{
"id": "EH",
"localLanguageName": "Arabic, French",
"localLanguageCode": "ARA, FRE"
"t5": [{
"id": ""
.
.
.
}]
}]
}]
}]
}]
}]
我正在寻找对数据进行分组的最有效方法。使用 HashMap 更好吗?或者 Javascript 中的 map/reduce 方法?
我已经尝试过以下方法。它显然不完整,但经过几次迭代后我陷入了困境。
const result = Object.values(data.reduce((key, curr) => {
const { region, country, t2, t3, t4, t5, t6, t7 } = curr;
if (!key[country]) {
let obj = {};
obj.region = region;
obj.country = country;
obj.t2 = [{
id: t2,
t3: [{
id: t3,
t4: {
id: t4,
t5: t5
}
}]
}];
key[country] = obj;
} else {
key[country].t2 = key[country].t2 || [];
const foundCountry = key[country].t2.find(x => x.desc === t2);
if (!foundCountry) {
key[country].t2.push({
id: t2,
t3: [{
id: t3,
t4: {
id: t4,
t5: t5
}
}]
});
} else {
const tx = foundCountry.find(x => x.id === t3);
if (!tx) {
foundCountry.push({
id: t3,
t4: {
id: t4,
t5: t5
}
});
} else {
tx.id = t3;
tx.t4 = t4;
}
}
}
return key;
}, {}));
console.log(util.inspect(result, false, null, true))
return result;
最佳答案
这个答案提供了两种解决方案:
- 以关卡为中心的方法,具有处理每个关卡的自定义函数。
- 使用给定键数组和统一结果集的快速方法。
每个级别的短路自定义功能
此方法对每个级别采用不同的 View ,并允许结束特定节点的迭代。
result = data.reduce((r, o) => {
let p = r;
groups.every(fn => p = fn(o, p));
return r;
}, []);
上面的代码迭代给定的数据集并使用分组函数的数组,该函数返回 truthy或falsy值(value)。如果出现假值,迭代将在此级别停止。
({ region }, target) => { // 1
if (!region) return; // 2
let temp = target.find(q => q.region === region); // 3
if (!temp) target.push(temp = { region, country: [] }); // 4
return temp.country; // 5
}
分组函数至少有四到五个部分。
函数签名包含源对象或通过 destructuring 的子集和一个目标。目标可以是数组或对象。
检查分组值是否存在,如果不存在则返回。这也结束了所有后续组的迭代。这一点是可选的。
搜索寻找所需群组的正确对象。
检查该组是否存在,如果不存在,则创建一个具有所需属性的新组
函数的返回值,可以是数组,也可以是对象,具体取决于下一个分组函数。
这种方法的主要优点是能够使用自定义结构处理不同级别,并且可以省略空/未给定的分组值。
主要缺点是每个级别都有一个功能。
const
groups = [
({ region }, target) => {
if (!region) return;
let temp = target.find(q => q.region === region);
if (!temp) target.push(temp = { region, country: [] });
return temp.country;
},
({ country: desc }, target) => {
if (!desc) return;
let temp = target.find(q => q.desc === desc);
if (!temp) target.push(temp = { desc, t2: [] });
return temp.t2;
},
({ t2: id, localLanguage: { localLanguageName, localLanguageCode } }, target) => {
if (!id) return;
let temp = target.find(q => q.id === id);
if (!temp) target.push(temp = { id, localLanguageName, localLanguageCode, t3: [] });
return temp.t3;
},
({ t3: id }, target) => {
if (!id) return;
let temp = target.find(q => q.id === id);
if (!temp) target.push(temp = { id, t4: [] });
return temp.t4;
},
({ t4: id }, target) => {
if (!id) return;
let temp = target.find(q => q.id === id);
if (!temp) target.push(temp = { id, t5: [] });
return temp.t5;
}
],
data = [{ region: null, country: null, territory: "Worldwide", territoryCode: "ALL", t2: null, t3: null, t4: null, t5: null, t6: null, t7: null, localLanguage: { territoryId: 1, localLanguageName: "N/A", localLanguageCode: null } }, { region: "Africa", country: "Madagascar", territory: null, territoryCode: "MG", t2: "AFR", t3: "MG", t4: null, t5: null, t6: null, t7: null, localLanguage: { territoryId: 30, localLanguageName: "Malagasy, French", localLanguageCode: "MLG, FRE" } }, { region: "Africa", country: null, territory: null, territoryCode: "AFR", t2: "AFR", t3: null, t4: null, t5: null, t6: null, t7: null, localLanguage: { territoryId: 2, localLanguageName: "N/A", localLanguageCode: null } }, { region: "Africa", country: "Morocco (incl. Western Sahara)", territory: null, territoryCode: "MA", t2: "AFR", t3: "MA", t4: null, t5: null, t6: null, t7: null, localLanguage: { territoryId: 35, localLanguageName: "Arabic, French", localLanguageCode: "ARA, FRE" } }, { region: "Africa", country: "Morocco (incl. Western Sahara)", territory: "Morocco (excl. Western Sahara)", territoryCode: "MAXEH", t2: "AFR", t3: "MA", t4: "MAXEH", t5: null, t6: null, t7: null, localLanguage: { territoryId: 36, localLanguageName: "Arabic, French", localLanguageCode: "ARA, FRE" } }, { region: "Africa", country: "Morocco (incl. Western Sahara)", territory: "Western Sahara", territoryCode: "EH", t2: "AFR", t3: "MA", t4: "EH", t5: null, t6: null, t7: null, localLanguage: { territoryId: 37, localLanguageName: "Arabic, French", localLanguageCode: "ARA, FRE" } }],
result = data.reduce((r, o) => {
let p = r;
groups.every(fn => p = fn(o, p));
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
快速统一的方法,每个级别都有相同的结构
{ id, children: [] }
这是每个级别的结果结构。 id
反射(reflect)实际的组值,children 包含相同结构的其他对象或最终对象。
此方法采用一个对象来表示关卡的所有键以及内部的结果_
。
它首先使用值过滤顶部组,然后通过从(最终)对象中提取 level 属性来减少组。
如果实际级别的组不存在,则会创建带有数组的新属性。该对象包含一个带有空数组的属性_
。该数组与该级别子级的后续可见对象共享相同的对象引用。
在缩减结束时,将推送没有访问过的属性的最终对象。
最后返回下划线属性,因为它包含所有嵌套组。
<小时/>这种方法的主要优点是通过给定的键立即添加所需的分组。
主要的缺点是得到一个通用的结果,它不提供特定级别的定制。它不会过滤不需要的对象。
const
keys = ['region', 'country', 't2', 't3', 't4', 't5', 't6', 't7'],
data = [{ region: null, country: null, territory: "Worldwide", territoryCode: "ALL", t2: null, t3: null, t4: null, t5: null, t6: null, t7: null, localLanguage: { territoryId: 1, localLanguageName: "N/A", localLanguageCode: null } }, { region: "Africa", country: "Madagascar", territory: null, territoryCode: "MG", t2: "AFR", t3: "MG", t4: null, t5: null, t6: null, t7: null, localLanguage: { territoryId: 30, localLanguageName: "Malagasy, French", localLanguageCode: "MLG, FRE" } }, { region: "Africa", country: null, territory: null, territoryCode: "AFR", t2: "AFR", t3: null, t4: null, t5: null, t6: null, t7: null, localLanguage: { territoryId: 2, localLanguageName: "N/A", localLanguageCode: null } }, { region: "Africa", country: "Morocco (incl. Western Sahara)", territory: null, territoryCode: "MA", t2: "AFR", t3: "MA", t4: null, t5: null, t6: null, t7: null, localLanguage: { territoryId: 35, localLanguageName: "Arabic, French", localLanguageCode: "ARA, FRE" } }, { region: "Africa", country: "Morocco (incl. Western Sahara)", territory: "Morocco (excl. Western Sahara)", territoryCode: "MAXEH", t2: "AFR", t3: "MA", t4: "MAXEH", t5: null, t6: null, t7: null, localLanguage: { territoryId: 36, localLanguageName: "Arabic, French", localLanguageCode: "ARA, FRE" } }, { region: "Africa", country: "Morocco (incl. Western Sahara)", territory: "Western Sahara", territoryCode: "EH", t2: "AFR", t3: "MA", t4: "EH", t5: null, t6: null, t7: null, localLanguage: { territoryId: 37, localLanguageName: "Arabic, French", localLanguageCode: "ARA, FRE" } }],
result = data
.reduce((t, o) => {
const groups = keys.filter((flag => k => flag = flag && o[k])(true));
groups
.reduce(function (r, k) {
let id;
({ [k]: id, ...o } = o);
if (!r[id]) {
r[id] = { _: [] };
r._.push({ id, children: r[id]._ });
}
return r[id];
}, t)._.push(o);
return t;
}, { _: [] })
._;
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
很难理解规范解决方案应该覆盖给定数据集的哪一部分、是否或任何数据集以及目标操作正在寻找什么。因此,这个答案由两部分组成,但如果给出提示,任何人都会受益。
关于javascript - 按对象数组javascript中的多个键进行分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60943243/