Łukasz
Łukasz

Reputation: 39

Filter through multiple levels nested array

I have a list which could look like this:

let list = [
  {
    name: "Level 1",
    children: [
      {
        name: "Level 2",
        children: [
          {
            name: "Level 3A",
            children: [],
          },
          {
            name: "Level 3B",
            children: [],
          },
          {
            name: "Level 3C",
            children: [],
          },
        ],
      },
    ],
  },
];

As you can see it consists of elements with 2 properties: name and children. This is simple list but it can be nested many levels down and each element could have a lot of children.

Moreover i have sample array of arrays of strings like this:

const filterRows = [
    ["Level 1", "Level 2", "Level 3A"],
    ["level 1", "Level 2", "Level 3C"]
]

Each of this 2 arrays of strings represents each 'row' in my list. (Here we don't have ["level 1", "Level 2", "Level 3B"])

My goal is to make something like filter. So based on filterRows i want my list to be:

let filteredList = [
    {
      name: "Level 1",
      children: [
        {
          name: "Level 2",
          children: [
            {
              name: "Level 3A",
              children: [],
            },
            {
              name: "Level 3C",
              children: [],
            },
          ],
        },
      ],
    },
  ];

As you can see in filteredList we only have rows specified in filterRows (so here we don't have "Level 3B")

Could you help me create function to do that?

As i said list (initial list) could be much more complicated I simplify it. Also filterRows can be different (but always correctly represent some rows in our list). So it cannot be hardcoded.

Upvotes: 0

Views: 538

Answers (1)

Nina Scholz
Nina Scholz

Reputation: 386786

With matching strings, you could build a tree and rebuild the structure with the wanted items.

const
    filter = level => (r, { name, children }) => {
        const next = level[name];
        if (next) {
            if (Object.keys(next).length) children = children.reduce(filter(next), []);
            r.push({ name, children });
        }
        return r;
    },
    list = [{ name: "Level 1", children: [{ name: "Level 2", children: [{ name: "Level 3A", children: [] }, { name: "Level 3B", children: [] }, { name: "Level 3C", children: [] }] }] }],
    filterRows =  [["Level 1", "Level 2", "Level 3A"], ["Level 1", "Level 2", "Level 3C"]],
    tree = filterRows.reduce((r, a) => {
        a.reduce((o, k) => o[k] ??= {}, r);
        return r;
    }, {}),
    result = list.reduce(filter(tree), []);

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

Upvotes: 2

Related Questions