【问题标题】:How do I create a flat array from a nested array of objects in javascript recursively?如何从javascript中的嵌套对象数组递归创建平面数组?
【发布时间】:2021-03-04 09:22:54
【问题描述】:

我要转换如下数据结构:

const data = [
  {
    regions: ['United States', 'Canada']
  },
  {
    regions: ['United States']
  },
  {
    prop1: {
      regions: ['Canada']
    }
  },
  {
    prop2: [
      {
        regions: ['Mexico', 'United States'],
        prop3: {
          regions: ['Canada']
        }
      }
    ]
  }
];

进入如下数据结构:

['United States', 'Canada', 'United States', 'Canada', 'Mexico', 'United States', 'Canada']

为了安全起见,我希望通过 ES6 递归地使用 .reduce.map 来执行此操作。

这是我迄今为止尝试过的,但它只有 2 个级别:

export const flattenArray = (arr: Object[], prop: string): any[] =>
  arr.reduce(
    (a, c) => [
      ...new Set([
        ...a,
        ...c.map(x => x[prop]).reduce((y, z) => [...y, ...z.map(j => j)], []),
      ]),
    ],
    []
  );

更新:我没有使用@deterjan 和他的解决方案。万一有人需要非.flat 版本,这是他在.reduce 的单一功能中的解决方案

export const flatten = (obj: any, prop: string): any[] => [
  ...new Set(
    Object.keys(obj).reduce((a, c) => {
      if (c === prop) {
        if (isArray(obj[prop])) {
          return [...a, ...obj[c]];
        } else {
          return [...a, obj[c]];
        }
      } else if (isArray(obj[c])) {
        return [
          ...a,
          ...obj[c].reduce((a, c) => [...a, ...flatten(c, prop)], []),
        ];
      } else if (isObject(obj)) {
        return [...a, ...flatten(obj[c], prop)];
      } else {
        return a;
      }
    }, [])
  ),
];

console.log(flatten(data, 'regions'));

【问题讨论】:

  • 你尝试过什么,你在挣扎什么?
  • @ThomasSablik 我已经将我目前尝试过的内容添加到帖子中。

标签: javascript dictionary ecmascript-6 reduce flatten


【解决方案1】:

不确定这是否是您要查找的内容,但以下代码递归地将对象和数组映射到它们的“区域”键,在每一步都变平。

function isArray(what) {
    return Object.prototype.toString.call(what) === '[object Array]';
}

function searchObj(obj) {
    return Object.keys(obj).map(key => {
        if (key == "regions" && isArray(obj.regions)) return obj[key];
        else if (isArray(obj[key])) return searchArray(obj[key]);
        else if (typeof obj === "object") return searchObj(obj[key]);
        else return [];
    }).flat();
}

function searchArray(obj) {
    return obj.map(elem => searchObj(elem)).flat();
}

用法:

searchObj(data)
> ["United States", "Canada", "United States", "Canada", "Mexico", "United States", "Canada"]

编辑:这是来自https://unpkg.com/array-flat-polyfill@1.0.1/index.js 的 Array.flat() 填充物

Array.prototype.flat||Object.defineProperty(Array.prototype,"flat",{configurable:!0,value:function r(){var t=isNaN(arguments[0])?1:Number(arguments[0]);return t?Array.prototype.reduce.call(this,function(a,e){return Array.isArray(e)?a.push.apply(a,r.call(e,t-1)):a.push(e),a},[]):Array.prototype.slice.call(this)},writable:!0}),Array.prototype.flatMap||Object.defineProperty(Array.prototype,"flatMap",{configurable:!0,value:function(r){return Array.prototype.map.apply(this,arguments).flat()},writable:!0})

【讨论】:

  • 是的,我认为这很棒,我只需要弄清楚如何在不使用.flat() 的情况下做到这一点,因为我需要支持 IE。比如.reduce.map
  • 编辑了添加 polyfill 的答案,您还可以使用自定义函数进行展平,这对于使用 reduce() 和 concat() 实现是微不足道的。
  • 谢谢!这非常有帮助,我一直陷入递归以及在哪里做这件事 - 这对我帮助很大。
【解决方案2】:

这是一个使用对象作为 json 的解决方案,然后使用正则表达式在其中搜索。我想存在其他方式来构建正则表达式以更好的方式,因为我不得不使用替换方法来删除引号。你可以使用一些工具来衡量性能。

const data = {
  sourceId: {
    S: "some_string"
  },
  ignored: {
    BOOL: false
  },
  stepFunctionArn: {
    S: "some_string"
  },
  certificate: {
    BOOL: true
  },
  infoNeeded: {
    L: [
      "Array"
    ]
  },
  queuesLinks: {
    M: [
      "Object"
    ]
  },
};


[...JSON.stringify(data).matchAll(/(?:\"regions\"\:\[)(?:\")(.*?)(?:\")\]/gi)].reduce(function(a, v) {
  a = a.concat(v[1].replace(/\"/g,"").split(','));
  return a;
}, [])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-20
    • 2020-10-06
    • 2019-02-08
    • 2020-08-01
    • 1970-01-01
    • 2015-04-11
    • 1970-01-01
    相关资源
    最近更新 更多