🍊

> こういうフラットな配列から木構造を作るのってどうやったらいいんだろう?

2021/05/11に公開

Of https://twitter.com/suin/status/1390626681547751429

interface Chapter {
    level: number;
    text: string;
}
interface ChapterNode extends Chapter {
    children: ChapterNode[];
}
const input = [
    { level: 1, text: "1章" },
    { level: 1, text: "2章" },
    { level: 2, text: "2.1" },
    { level: 2, text: "2.2" },
    { level: 1, text: "第3章" },
    { level: 2, text: "3.1" },
    { level: 2, text: "3.2" },
    { level: 3, text: "3.2.1" },
    { level: 3, text: "3.2.2" },
];
const treefy = (queue: Chapter[], level = 1): ChapterNode[] =>
    queue.reduce(
        (acc, cur, idx, array) =>
            cur.level === level
                ? acc.concat({
                    ...cur,
                    children: treefy(
                        takeWhile((c) => c.level >= level + 1, array.slice(idx + 1)),
                        level + 1
                    ),
                })
                : acc,
        [] as ChapterNode[]
    );
const takeWhile = <T>(func: (head: T) => boolean, accum: T[]): T[] =>
    accum.length && func(accum[0])
        ? [accum[0], ...takeWhile(func, accum.slice(1))]
        : ([] as T[]);
console.log(JSON.stringify(treefy(input), null, 2));
$ deno run treefy.ts
[
  {
    "level": 1,
    "text": "1章",
    "children": []
  },
  {
    "level": 1,
    "text": "2章",
    "children": [
      {
        "level": 2,
        "text": "2.1",
        "children": []
      },
      {
        "level": 2,
        "text": "2.2",
        "children": []
      }
    ]
  },
  {
    "level": 1,
    "text": "第3章",
    "children": [
      {
        "level": 2,
        "text": "3.1",
        "children": []
      },
      {
        "level": 2,
        "text": "3.2",
        "children": [
          {
            "level": 3,
            "text": "3.2.1",
            "children": []
          },
          {
            "level": 3,
            "text": "3.2.2",
            "children": []
          }
        ]
      }
    ]
  }
]

Gist

Discussion