我将如何改变它?

How would I transform this?

我想为以下转换找到一个很好的优雅解决方案。如何以最简单的方式(可选地使用功能库 Ramda)最好地实现这一点?

const data = [
  {
    id: 'a',
  },
  {
    id: 'b',
    routes: [
      {
        id: 'c',
      },
      {
        id: 'd',
        routes: [
          {
            id: 'e',
          }
        ]
      }
    ]
  }
];

const expected = [
  {
    id: 'a',
  },
  {
    id: 'b',
  },
  {
    id: 'c',
  },
  {
    id: 'd',
  },
  {
    id: 'e',
  }
];

这是一个普通的 JS 解决方案,使用 reduce 和递归:

const data = [
  {
    id: 'a',
  },
  {
    id: 'b',
    routes: [
      {
        id: 'c',
      },
      {
        id: 'd',
        routes: [
          {
            id: 'e',
          }
        ]
      }
    ]
  }
];

const transform = arr => arr.reduce((a, { id, routes }) => (
  [...a, { id }, ...transform(routes || [])]
), []);
console.log(transform(data));

或者,您可以简单地推送到现有数组,而不是每次都创建新数组:

const data = [{
    id: 'a',
  },
  {
    id: 'b',
    routes: [{
        id: 'c',
      },
      {
        id: 'd',
        routes: [{
          id: 'e',
        }]
      }
    ]
  }
];

const transform = (arr, pushTo = []) => arr.reduce((a, { id, routes }) => {
  a.push({ id });
  if (routes) transform(routes, a);
  return a;
}, pushTo);
console.log(transform(data));

使用变量嵌套 属性 而不是 routes 硬编码:

const data = [{
    id: 'a',
  },
  {
    id: 'b',
    routes: [{
        id: 'c',
      },
      {
        id: 'd',
        routes: [{
          id: 'e',
        }]
      }
    ]
  }
];

const transform = (arr, prop, pushTo = []) => arr.reduce((a, item) => {
  const nested = item[prop];
  a.push({ id: item.id });
  if (nested) transform(nested, prop, a);
  return a;
}, pushTo);
console.log(transform(data, 'routes'));

没有过多传播的JS解决方案

function getFlat(array = []) {
    return array.reduce((r, { id, routes }) => r.concat({ id }, getFlat(routes)), []);
}

const data = [{ id: 'a', }, { id: 'b', routes: [{ id: 'c', }, { id: 'd', routes: [{ id: 'e', }] }] }];

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

使用对象的剩余参数获取对象的所有属性,return 除外 routes

function getFlat(array = []) {
    return array.reduce((r, { routes, ...o }) => r.concat(o, getFlat(routes)), []);
}

const data = [{ id: 'a', foo: 1 }, { id: 'b', routes: [{ id: 'c' }, { id: 'd', routes: [{ id: 'e', bar: 2 }] }] }];

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

此处其他建议的替代方法是使用 R.chain 展平每组嵌套路由。

const fn = R.chain(({routes = [], ...rest}) => [{...rest}, ...fn(routes)])

一旦 Array.prototype.flatMap 变得可用,这种方法也可以通过普通 JS 实现。

const fn = (xs = []) => xs.flatMap(({routes, ...rest}) => [{...rest}, ...fn(routes)])