首页 > 解决方案 > 在 JS 中使用深度文字键减少对象数组

问题描述

我对使用 reduce 方法进行数组转换感到困惑。我不知道如何用文字键处理嵌套对象。

为了带来一些优势,我将发布一些我写的例子,它工作正常:

// 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"
        }
    }
}
*/

此时我正在编写这种reduce函数。它有效,但它只给了我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"
        }
    }
}
*/

任何帮助,请。

标签: javascriptarraysdictionaryobjectreduce

解决方案


您可以使用一组想要的键进行分组,然后将值或新对象用于下一级。

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; }

方法是获取对象的所有值并将最后一项分配为最嵌套对象的值。

这种方法依赖于每个对象中值的顺序。

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; }


推荐阅读