網站搜尋

javascript - 如何根據帶有表示層級的枚舉列表的字段,將平面陣列轉換為層級樹列表


我正在嘗試將一個平面的帳戶餘額清單轉換為基於唯一代碼清單的層級帳戶樹清單。我對如何解決這個問題感到困惑,因為我看不出應該採取哪些步驟。

如果你想像一個 Excel 表格,那麼帳戶餘額將是一行,而代碼欄位表示該行被拆分成多少層。這實際上意味著,第一個 codes[0] 是第一層,codes[1] 將是下一層,如此類推。通過將帳戶餘額轉換為帳戶樹,我想正確計算每一層(codeType 和 code)的 amountOut,然後將其作為帳戶樹添加到 subAccounts 陣列中。

下面我已經添加了所有使用的類型,並提供了輸入和輸出的範例。

interface AccountBalance {
    id: string
    codes: Code[]
    amountOut: number
}

type Code = {
    id: string
    codeType: CodeTypes
    code: string
    description: string
}

enum CodeTypes {
    account = "account",
    responsible = "responsible",
    project = "project",
    object = "object",
    counterPart = "counterPart",
    free = "free",
}

type AccountTree = {
    id: string
    name: string
    code: string
    amountOut: number
    subAccounts: AccountTree[]
}

輸入範例:

const accountBalances: AccountBalance[] = [
            {
                id: "671769fbd36fcd6c2c7f2d9b",
                codes: [
                    {
                        id: "671769fbd36fcd6c2c7f2c2d",
                        codeType: codeTypeEnum.account,
                        code: "1250",
                        description: "Column A",
                    },
                    {
                        id: "671769fbd36fcd6c2c7f2bd5",
                        codeType: codeTypeEnum.responsible,
                        code: "17",
                        description: "Column B",
                    },
                    {
                        id: "671769fbd36fcd6c2c7f2bf7",
                        codeType: codeTypeEnum.counterPart,
                        code: "20",
                        description: "Column C",
                    },
                ],
                amountOut: 24510549,
            },
            {
                id: "671769fbd36fcd6c2c7f2d9c",
                codes: [
                    {
                        id: "671769fbd36fcd6c2c7f2c2d",
                        codeType: codeTypeEnum.account,
                        code: "1250",
                        description: "Column A",
                    },
                    {
                        id: "671769fbd36fcd6c2c7f2bee",
                        codeType: codeTypeEnum.responsible,
                        code: "40",
                        description: "Column B",
                    },
                    {
                        id: "671769fbd36fcd6c2c7f2c08",
                        codeType: codeTypeEnum.counterPart,
                        code: "S3",
                        description: "Column C",
                    },
                ],
                amountOut: 0,
            },
            {
                id: "671769fbd36fcd6c2c7f2d9d",
                codes: [
                    {
                        id: "671769fbd36fcd6c2c7f2c2d",
                        codeType: codeTypeEnum.account,
                        code: "1250",
                        description: "Column A",
                    },
                    {
                        id: "671769fbd36fcd6c2c7f2bdb",
                        codeType: codeTypeEnum.responsible,
                        code: "80",
                        description: "Column B",
                    },
                    {
                        id: "671769fbd36fcd6c2c7f2bdc",
                        codeType: codeTypeEnum.counterPart,
                        code: "52",
                        description: "Column C",
                    },
                ],
                amountOut: 6381398,
            },
        ]

我想要的輸出,例如:

const expected: AccountTree = {
            id: "671769fbd36fcd6c2c7f2c2d",
            name: "Column A",
            code: "1250",
            amountOut: 30891947,
            subAccounts: [
                {
                    id: "671769fbd36fcd6c2c7f2bd5",
                    name: "Column B",
                    code: "17",
                    amountOut: 24510549,
                    subAccounts: [
                        {
                            id: "671769fbd36fcd6c2c7f2bf7",
                            name: "Column C",
                            code: "20",
                            amountOut: 24510549,
                            subAccounts: [],
                        },
                    ],
                },
                {
                    id: "671769fbd36fcd6c2c7f2bee",
                    name: "Column B",
                    code: "40",
                    amountOut: 0,
                    subAccounts: [
                        {
                            id: "671769fbd36fcd6c2c7f2c08",
                            name: "Column C",
                            code: "S3",
                            amountOut: 0,
                            subAccounts: [],
                        },
                    ],

                },
                {
                    id: "671769fbd36fcd6c2c7f2bdb",
                    name: "Column B",
                    code: "80",
                    amountOut: 6381398,
                    subAccounts: [
                        {
                            id: "671769fbd36fcd6c2c7f2bdc",
                            name: "Column C",
                            code: "52",
                            amountOut: 6381398,
                            subAccounts: [],
                        },
                    ],
                },
            ],
        }

到目前為止我得到的是這個

const uniqueCodeTypes = [
        ...new Set(
            accountBalances.reduce<CodeTypes[]>(
                (acc, balance) => [
                    ...acc,
                    ...balance.codes.flatMap((code) => code.codeType),
                ],
                [],
            ),
        ),
    ]

    const uniqueCodesForCodeType = uniqueCodeTypes.map((codeType) => {
        const uniqueCodesForCodeType = [
            ...new Map(
                accountBalances.reduce<Code[]>((acc, balance) => {
                    const code = balance.codes.find(
                        (code) => code.codeType === codeType,
                    )
                    return code ? [...acc, code] : acc
                }, []).map((code) => [code.code, code])
            ).values(),
        ]
        return uniqueCodesForCodeType
    })

但我不確定之後該如何進行。

答案#1

在純 Javascript 中,你可以在同一層級搜尋 id,如果不存在則添加對象。

const
    codeTypeEnum = { account: "account", responsible: "responsible", project: "project", object: "object", counterPart: "counterPart", free: "free"},
    accountBalances = [{ id: "671769fbd36fcd6c2c7f2d9b", codes: [{ id: "671769fbd36fcd6c2c7f2c2d", codeType: codeTypeEnum.account, code: "1250", description: "Column A" }, { id: "671769fbd36fcd6c2c7f2bd5", codeType: codeTypeEnum.responsible, code: "17", description: "Column B" }, { id: "671769fbd36fcd6c2c7f2bf7", codeType: codeTypeEnum.counterPart, code: "20", description: "Column C" }], amountOut: 24510549 }, { id: "671769fbd36fcd6c2c7f2d9c", codes: [{ id: "671769fbd36fcd6c2c7f2c2d", codeType: codeTypeEnum.account, code: "1250", description: "Column A" }, { id: "671769fbd36fcd6c2c7f2bee", codeType: codeTypeEnum.responsible, code: "40", description: "Column B" }, { id: "671769fbd36fcd6c2c7f2c08", codeType: codeTypeEnum.counterPart, code: "S3", description: "Column C" }], amountOut: 0 }, { id: "671769fbd36fcd6c2c7f2d9d", codes: [{ id: "671769fbd36fcd6c2c7f2c2d", codeType: codeTypeEnum.account, code: "1250", description: "Column A" }, { id: "671769fbd36fcd6c2c7f2bdb", codeType: codeTypeEnum.responsible, code: "80", description: "Column B" }, { id: "671769fbd36fcd6c2c7f2bdc", codeType: codeTypeEnum.counterPart, code: "52", description: "Column C" }], amountOut: 6381398 }],
    result = accountBalances.reduce((r, { amountOut, codes }) => {
        codes.reduce((level, o) => {
            let target = level.find(({ id, codeType }) => id === o.id && codeType === o.codeType);
            if (!target) {
                target = { ...o, amountOut: 0, subAccounts: [] };
                level.push(target);
            }
            target.amountOut += amountOut;
            return target.subAccounts;
        }, r);

        return r;
    }, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }