[英]Reduce array of objects with deeply literals keys in JS
我对使用 reduce 方法进行数组转换感到困惑。 我不知道如何用文字键处理嵌套的 object 。
为了带来一些优势,我将发布一些我写的例子,它工作正常:
// consider flat array of objects
const names = [
{ name: "Jaden", sname: "Smith", age: 33 },
{ name: "Will", sname: "Smith", age: 12 },
{ name: "Jada", sname: "Smith", age: 29 },
{ name: "Jose", sname: "Varho", age: 21 },
{ name: "Josephina", sname: "Varho", age: 44 },
{ name: "Keanu ", sname: "Reeves", age: 44 }] ;
// suppose i need to transform that array to this shape:
/* {
"Smith": {
"Jaden": 33,
"Will": 12,
"Jada": 29
},
"Varho": {
"Jose": 21,
"Josephina": 44
},
"Reeves": {
"Keanu ": 44
}
}
*/
// this reducer do it's fine:
const shapeIt = (acc, item) => {
console.log('acc:', JSON.stringify(acc));
acc[item.sname] = { ...acc[item.sname], [item.name]: item.age }
return acc
}
const transformShape= (arr) => {
return arr.reduce((acc, item) => shapeIt(acc, item), {});
}
transformShape(names); //gives required shape
所以现在,让我们想象一下我有更复杂的数组,比如:
const flatArray = [
{ "blockId": "first-block", "sectionId": "first-section", "fieldId": "_1", "value": "0" },
{ "blockId": "first-block", "sectionId": "first-section", "fieldId": "_2", "value": "1" },
{ "blockId": "first-block", "sectionId": "second-section", "fieldId": "_1", "value": "1" },
{ "blockId": "second-block", "sectionId": "first-section", "fieldId": "_1", "value": "1" },
{ "blockId": "second-block", "sectionId": "some-section", "fieldId": "_2", "value": "3" },
{ "blockId": "third-block", "sectionId": "other-section", "fieldId": "_1", "value": "3" }];
// and i strictly need to get this shape of object:
/* {
"first-block": {
"first-section": {
"_1": "0",
"_2": "1"
},
"second-section": {
"_1": "1"
}
},
"second-block": {
"first-section": {
"_1": "1"
},
"some-section": {
"_2": "3"
}
},
"third-block": {
"other-section": {
"_1": "3"
}
}
}
*/
此时我正在写这种减少function。 它有效,但它只给了我块中每个部分的最后一个fieldId
键。 如果一个块中的部分有多个fieldId
- 它会丢失它。 我正在寻找一个累加器,并看到只有具有不同 blockId、sectionId 的键被累加,而不是不同的fieldId
。
const shapeComplex = (acc, item) => {
console.log('acc:', JSON.stringify(acc));
acc[item.blockId] = { ...acc[item.blockId], [item.sectionId]: { [item.fieldId]: item.value } }
return acc
}
const transformComplex = (arr) => {
console.log('initialArr: ', arr)
return arr.reduce((acc, item) => shapeComplex(acc, item), {});
}
transformComplex(flatArray);
// it gives me shape with only last idField in same section and block:
/*
{
"first-block": {
"first-section": {
"_1": "0"
},
"second-section": {
"_1": "1"
}
},
"second-block": {
"first-section": {
"_1": "1"
},
"some-section": {
"_2": "3"
}
},
"third-block": {
"other-section": {
"_1": "3"
}
}
}
*/
任何帮助,请。
您可以使用一组想要的键进行分组,然后将值或新的 object 用于下一级别。
const data = [{ blockId: "first-block", sectionId: "first-section", fieldId: "_1", value: "0" }, { blockId: "first-block", sectionId: "first-section", fieldId: "_2", value: "1" }, { blockId: "first-block", sectionId: "second-section", fieldId: "_1", value: "1" }, { blockId: "second-block", sectionId: "first-section", fieldId: "_1", value: "1" }, { blockId: "second-block", sectionId: "some-section", fieldId: "_2", value: "3" }, { blockId: "third-block", sectionId: "other-section", fieldId: "_1", value: "3" }], keys = ['blockId', 'sectionId', 'fieldId'], result = data.reduce((r, o) => { keys.reduce( (q, k, i, { length }) => q[o[k]]??= i + 1 === length? o.value: {}, r ); return r; }, {}); console.log(result);
.as-console-wrapper { max-height: 100%;important: top; 0; }
通过获取 object 的所有值并将最后一项分配为最嵌套的 object 的值来接近。
这种方法依赖于每个 object 中值的顺序。
const data = [{ blockId: "first-block", sectionId: "first-section", fieldId: "_1", value: "0" }, { blockId: "first-block", sectionId: "first-section", fieldId: "_2", value: "1" }, { blockId: "first-block", sectionId: "second-section", fieldId: "_1", value: "1" }, { blockId: "second-block", sectionId: "first-section", fieldId: "_1", value: "1" }, { blockId: "second-block", sectionId: "some-section", fieldId: "_2", value: "3" }, { blockId: "third-block", sectionId: "other-section", fieldId: "_1", value: "3" }], result = data.reduce((r, o) => { const values = Object.values(o), value = values.pop(); values.reduce( (q, k, i, { length }) => q[k]??= i + 1 === length? value: {}, r ); return r; }, {}); console.log(result);
.as-console-wrapper { max-height: 100%;important: top; 0; }
您还需要复制最里面(部分)object 的属性(字段):
const shapeComplex = (acc, item) => {
console.log('acc:', JSON.stringify(acc));
acc[item.blockId] = {
...acc[item.blockId],
[item.sectionId]: {
...acc[item.blockId]?.[item.sectionId],
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[item.fieldId]: item.value
}
};
return acc
}
但是,我建议要么始终使用 object 分布在每个级别
const shapeComplex = (acc, item) => {
return {
...acc,
[item.blockId]: {
...acc[item.blockId],
[item.sectionId]: {
...acc[item.blockId]?.[item.sectionId],
[item.fieldId]: item.value
}
}
};
}
或使用突变:
const shapeComplex = (acc, {blockId, sectionId, fieldId, value}) => {
const block = acc[blockId] ?? (acc[blockId] = {});
const section = block[sectionId] ?? (block[sectionId] = {});
section[fieldId] = value;
return acc;
}
正如@Nina 在此处的答案中所示,您可以将其推广到任意深度的作业。
您可以执行以下操作,
const flatArray = [ { "blockId": "first-block", "sectionId": "first-section", "fieldId": "_1", "value": "0" }, { "blockId": "first-block", "sectionId": "first-section", "fieldId": "_2", "value": "1" }, { "blockId": "first-block", "sectionId": "second-section", "fieldId": "_1", "value": "1" }, { "blockId": "second-block", "sectionId": "first-section", "fieldId": "_1", "value": "1" }, { "blockId": "second-block", "sectionId": "some-section", "fieldId": "_2", "value": "3" }, { "blockId": "third-block", "sectionId": "other-section", "fieldId": "_1", "value": "3" }]; const shapeComplex = (acc, item) => { if(acc[item.blockId]) { acc[item.blockId] = {...acc[item.blockId], [item.sectionId]: {...acc[item.blockId][item.sectionId], [item.fieldId]: item.value } } } else { acc[item.blockId] = {...acc[item.blockId], [item.sectionId]: {[item.fieldId]: item.value } } } return acc } const transformComplex = (arr) => { return arr.reduce((acc, item) => shapeComplex(acc, item), {}); } console.log(transformComplex(flatArray));
您正在从平面数据结构中创建一棵树。 指定用于创建叶节点数据元素的树层次结构(级别)和属性。
例子:
function treeFrom (arr, levels, name, value) {
return arr.reduce(
(root,item) =>
{
var node = root;
for (let level of levels) /* descend to bottom tier */
{
levelvalue = item[level];
if (! node[levelvalue]) node[levelvalue] = {};
node = node[levelvalue];
}
node[item[name]] = item[value];
return root;
}
,
{}
)
}
console.log ( treeFrom(flatArray, ['blockId', 'sectionId'], 'fieldId', 'value') );
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.