你不知道的flatten函数

前言

因为es2019对数组增加了flat方法,最近讨论flat的频率也有所提高,各位大佬各显神通已经写了很多,如果我今天在这讨论flat有几种递归写法,那就没有什么意义了,所以今天我们讨论些不同的,我们讨论怎么写出迭代的flat

提出问题

先提出4个问题

  1. 你能实现一个将数组展平的函数吗?
  2. 你能实现一个可以传入展平深度参数的flat函数吗?
  3. 你能实现一个迭代版本的数组展平函数吗?
  4. 你能实现一个迭代版本的可传入展平深度参数的flat函数吗?

你先思考下,如果你都能写出来,就不用继续浪费时间啦?5s后揭开答案

5

4

3

2

1

flat递归版本


function flat(arr) {
  return arr.reduce((pre, cur) => {
    return [...pre, ...(Array.isArray(cur) ? flat(cur) : [cur])];
  }, []);
}
复制代码

带depth参数的flat递归版本

function flat(arr, depth = 1) {
  return depth > 0
    ? arr.reduce((pre, cur) => {
        return [...pre, ...(Array.isArray(cur) ? flat(cur, depth - 1) : [cur])];
      }, [])
    : arr;
}
复制代码

接下来是重点

flat迭代版本
其实就是树的前序遍历迭代写法,有一点需要注意的是,栈是后进先出的,所以在压栈的时候要从数组的最后一个元素开始压,这样弹出的顺序就是从数组的本身的顺序了。

function flat(arr, depth = 1) {
  let ret = [];
  let s = [];
  if (arr.length > 0) {
    for (let i = arr.length - 1; i >= 0; i--) {
      s.push(arr[i]);
    }
  }
  while (s.length > 0) {
    let cur = s.pop();
    if (Array.isArray(cur)) {
      for (let i = cur.length - 1; i >= 0; i--) {
        s.push(cur[i]);
      }
    } else {
      ret.push(cur);
    }
  }
  return ret;
}
复制代码

带depth参数的flat递归版本
我们在递归的时候函数调用栈可以保存我们的状态,这样我们就不用额外记录当前递归的深度了,但是迭代的时候呢?我们怎样保存当前栈顶元素被faltten了几次呢?我想的一个可选的方法是用另一个栈来保存当前栈顶元素被flatten了几次如果到达了指定的次数直接返回即可,如果栈顶元素是数组需要继续faltten,那么将栈顶的状态减一即可。最终实现的效果就是始终保证两个栈的栈顶是一一对应的关系。

function flat(arr, depth = 1) {
  let ret = [];
  let s = [];
  let status = [];
  if (arr.length > 0) {
    for (let i = arr.length - 1; i >= 0; i--) {
      s.push(arr[i]);
      status.push(depth);
    }
  }
  while (s.length > 0) {
    let cur = s.pop();
    let curStatus = status.pop();
    if (Array.isArray(cur) && curStatus > 0) {
      for (let i = cur.length - 1; i >= 0; i--) {
        s.push(cur[i]);
        status.push(curStatus - 1);
      }
    } else {
      ret.push(cur);
    }
  }
  return ret;
}
复制代码

后记

最后,再见flatten

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值