objects 的递归数组追加 属性 children 计数

Recursive array of objects to append property children count

我需要递归循环遍历 object 的数组,每个 object object 都有一个 属性 label 需要修改为包括 children 计数。

看看这个例子:

const nodes = [{
  value: 'World',
  label: 'World',
  children: [{
    label: 'Europe',
    value: 'Europe',
    children: [
      {
        label: 'Albania',
        value: 'AL'
      },
      {
        label: 'BeNeLux',
        value: 'BeNeLux',
        children: [
          {
            label: 'The Netherlands',
            value: 'NL'
          },
          {
            label: 'Belgium',
            value: 'BE'
          },
          {
            label: 'Luxembourg',
            value: 'LU'
          }
        ]
      }
    ]
  }]
}]

预期输出为:

const expectedOutput = [{
  value: 'World',
  label: 'World (4)',
  children: [{
    label: 'Europe (4)',
    value: 'Europe',
    children: [
      {
        label: 'Albania',
        value: 'AL'
      },
      {
        label: 'BeNeLux (3)',
        value: 'BeNeLux',
        children: [
          {
            label: 'The Netherlands',
            value: 'NL'
          },
          {
            label: 'Belgium',
            value: 'BE'
          },
          {
            label: 'Luxembourg',
            value: 'LU'
          }
        ]
      }
    ]
  }]
}]

这就是我现在所做的工作,但它无法正常工作,因为如上文 expectedOutput 所述,Europe 的标签将是 Europe (4) 而我的版本计数 Europe (2) 因为它忽略了欧洲内部的 children。

export const getSortedNodesWithChildrenCountLabel = nodes => {
  return nodes
    .reduce(function f (output, node) {
      if (node?.children) {
        node.label += ` (${node.children.length})`
        node.children = node.children
          .reduce(f, [])
      }

      output.push(node)
      return output
    }, [])
}

您可以采用递归方法并从子项中获取计数并更新 label

这种方法会改变数据。

function update(nodes) {
    return nodes.reduce((count, node) => {
        if (node.children) {
            var subcount = update(node.children);
            node.label += ` (${subcount})`;
            return count + subcount;
        }
        return count + 1;
    }, 0);
}

const nodes = [{ value: 'World', label: 'World', children: [{ label: 'Europe', value: 'Europe', children: [{ label: 'Albania', value: 'AL' }, { label: 'BeNeLux', value: 'BeNeLux', children: [{ label: 'The Netherlands', value: 'NL' }, { label: 'Belgium', value: 'BE' }, { label: 'Luxembourg', value: 'LU' }] }] }] }];

update(nodes);

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

一个非变异版本,它通过外部调用的对象获取计数。

function fn(count = { count: 0 }) {
    return function ({ value, label, children }) {
        var sub = { count: 0 };
        if (children) {
            children = children.map(fn(sub)),
            label += ` (${sub.count})`;
            count.count += sub.count;
            return { value, label, children };
        }
        count.count++;
        return { value, label };
    };
}

const
    nodes = [{ value: 'World', label: 'World', children: [{ label: 'Europe', value: 'Europe', children: [{ label: 'Albania', value: 'AL' }, { label: 'BeNeLux', value: 'BeNeLux', children: [{ label: 'The Netherlands', value: 'NL' }, { label: 'Belgium', value: 'BE' }, { label: 'Luxembourg', value: 'LU' }] }] }] }],
    withCount = nodes.map(fn());        

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

您可以将儿童计数分解为单独的递归函数:

const nodes = [{
  value: 'World',
  label: 'World',
  children: [{
    label: 'Europe',
    value: 'Europe',
    children: [
      {
        label: 'Albania',
        value: 'AL'
      },
      {
        label: 'BeNeLux',
        value: 'BeNeLux',
        children: [
          {
            label: 'The Netherlands',
            value: 'NL'
          },
          {
            label: 'Belgium',
            value: 'BE'
          },
          {
            label: 'Luxembourg',
            value: 'LU'
          }
        ]
      }
    ]
  }]
}]

const getChildrenCount = (node, count = 0) => {
  if (!node.children) {
    return 1
  }
  for (const child of node.children) {
    count += getChildrenCount(child)
  }
  return count;
}

const getSortedNodesWithChildrenCountLabel = nodes => {
  return nodes
    .reduce(function f (output, node) {
      if (node.children) {
        node.label += ` (${getChildrenCount(node)})`
        node.children = node.children
          .reduce(f, [])
      }

      output.push(node)
      return output
    }, [])
}

console.log(getSortedNodesWithChildrenCountLabel(nodes))