极客时间返利平台,你可以在上边通过山月的链接购买课程,并添加我的微信 (shanyue94) 领取返现。
山月训练营之面试直通车 服务上线了,从准备简历、八股文准备、项目经历准备、面试、面经、面经解答、主观问题答复、谈薪再到入职的一条龙服务。

# 实现一个数组扁平化的函数 flatten

更多描述

flatten 模拟 Array.prototype.flat 实现,默认展开一层,可传递参数用以展开多层

// [1, 2, 3, 4, [5, 6]]
flatten([1, 2, 3, [4, [5, 6]]]);

// [1, 2, 3, 4, 5, 6]
flatten([1, 2, 3, [4, [5, 6]]], 2);

Issue

欢迎在 Gtihub Issue 中回答此问题: Issue 451 (opens new window)

在 ES2019 之前,可通过 reduce + concat 实现,由于 Array.prototype.concat 既可以连接数组又可以连接单项,十分巧妙

const flatten = (list) => list.reduce((a, b) => a.concat(b), []);

一个更简单的实现方式是 Array.prototype.concat... 运算符

const flatten = (list) => [].concat(...list);

如果要求深层数组打平,则如下实现

const flatten = (list) =>
  list.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);

如果要求如同原生 API Array.prototype.flat 一致的 API,可传入可扁平的深度。代码可见 【Q443】实现一个数组扁平化的函数 flatten (opens new window)

function flatten(list, depth = 1) {
  if (depth === 0) return list;
  return list.reduce(
    (a, b) => a.concat(Array.isArray(b) ? flatten(b, depth - 1) : b),
    []
  );
}

在 ES2019 之后,可通过 Array.prototype.flat 直接实现!

您好作者,您的实现方式最多只能降维一层深度。

const flatten = (list) =>
  list.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);

不仅如此,ES2019 的 flat 还支持传入**depth**来降维指定的深度。

@reveriesMeng 好的

const flatten = (arr, d = 1) => d > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatten(val, d - 1) : val), []) : arr.slice()
function flat(array, depth = Number.MAX_VALUE) {
  let result = [...array];
  while (result.some((i) => Array.isArray(i) && depth > 0)) {
    // 注意concat方法的参数valueN,即可是数值也可以是数组,当时数组时存在隐形的展开操作
    // concat方法不改变原数组,返回一个新数组
    result = [].concat(...result);
    depth--;
  }
  return result;
}

@haotie1990 原生 API 默认是 1,当然这个题目我也没有规定,不过 depth 用 MAX_SAFE_INTEGER 或者 Infinity 好一些?

而且该 API 也不涉及对数组自身的操作,应该无需 [...array]

function flatten(arr) {
return arr.reduce((result, item)=> { return result.concat(Array.isArray(item) ? flatten(item) : item); }, []); }

function flatten(arr) { return arr.toString().split(',').map(function(item) { return Number(item); }) }

Author

回答者: 3fuyang (opens new window)

一种使用迭代器的实现:

const flatten = function(target, depth = 1) {
  const copy = [...target]
  for(let i = 0; i < depth; ++i){
    const iter = copy[Symbol.iterator]()
    let item = null
    for(item = iter.next(); !item.done; ){
      // 注意:迭代器并不与可迭代对象某个时刻的快照绑定,而仅仅是用游标来记录遍历可迭代对象的历程,
      // 如果可迭代对象在迭代期间被修改了,那么迭代器也会反映相应的变化
      if(Array.isArray(item.value)){
        const temp = [...item.value]
        let size = temp.length
        for(let j = 0; j < size; ++j){
          item = iter.next()
        }
        copy.splice(copy.indexOf(item.value), 1, ...temp)
      }else{
        item = iter.next()
      }
    }
    /* for(let item of copy){
      if(Array.isArray(item)){
        const temp = [...item]
        copy.splice(copy.indexOf(item), 1, ...temp)
      }
    } */
  }
  return copy
}

Author

回答者: Vi-jay (opens new window)

支持 depth 为 0

function flatten(arr = [], depth = 1) {
  return arr.reduce(
    (acc, cur) =>
      acc.concat(
        Array.isArray(cur) && depth > 0 ? flatten(cur, --depth) : [cur]
      ),
    []
  );
}

Author

回答者: bldf (opens new window)

基于递归实现,不用 Array.concat

Array.prototype.myFlat = function (this: any[], depth: number = 1) {
  const myFlat = (
    arr: any[],
    flatLength = 1,
    resultArray = [] as any[],
    forEachCount = 0
  ) => {
    arr.forEach((d: any) => {
      if (
        Array.isArray(d) &&
        (flatLength === -1 || forEachCount < flatLength)
      ) {
        myFlat(d, flatLength, resultArray, forEachCount + 1);
      } else {
        resultArray.push(d);
      }
    });

    return resultArray;
  };

  return myFlat(this, depth);
};
Last Updated: 9/27/2022, 2:39:59 PM