Advanced-Frontend/Daily-Interview-Question

第 36 题:使用迭代的方式实现 flatten 函数

Moriarty02 opened this issue · 83 comments

var arr=[1,2,3,[4,5],[6,[7,[8]]]]
/**
 * 使用递归的方式处理
 * wrap内保存结果ret 
 * 返回一个递归函数
 *
 * @returns
 */
function wrap(){
    var ret=[];
    return function flat(a){
        for(var item of a){
            if(item.constructor===Array){
                ret.concat(flat(item))
            }else{
                ret.push(item)
            }
        }
        return ret
    }
}
console.log(wrap()(arr));

将一个多维数组拍平为一个一维数组

const spreadableSymbol = Symbol.isConcatSpreadable
const isFlattenable = (value) => {
  return Array.isArray(value) || (typeof value == 'object' && value !== null
    && Object.prototype.toString.call(value) === '[object Arguments]') ||
    !!(spreadableSymbol && value && value[spreadableSymbol])
}

/**
 * flatten的基本实现,具体可以参考lodash库的flatten源码
 * @param array 需要展开的数组
 * @param depth 展开深度
 * @param predicate 迭代时需要调用的函数
 * @param isStrict 限制通过`predicate`函数检查的值
 * @param result 初始结果值
 * @returns {Array} 返回展开后的数组
 */
function flatten(array, depth, predicate, isStrict, result) {
  predicate || (predicate = isFlattenable)
  result || (result = [])

  if (array == null) {
    return result
  }

  for (const value of array) {
    if (depth > 0 && predicate(value)) {
      if (depth > 1) {
        flatten(value, depth - 1, predicate, isStrict, result)
      } else {
        result.push(...value)
      }
    } else if (!isStrict) {
      result[result.length] = value
    }
  }
  return result
}

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

迭代的实现:

let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]

const flatten = function (arr) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr)
    }
    return arr
}

console.log(flatten(arr))

递归的实现(ES6简写):

const flatten = array => array.reduce((acc, cur) => (Array.isArray(cur) ? [...acc, ...flatten(cur)] : [...acc, cur]), [])
let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]

迭代实现

    function flatten(arr) {
      let arrs =[...arr]
      let newArr = [];
      while (arrs.length){
        let item = arrs.shift()
        if(Array.isArray(item)){
          arrs.unshift(...item)
        }else {
          newArr.push(item)
        }
      }
      return newArr
    }

递归实现

    function flatten(arr) {
    let arrs = [];
      arr.map(item => {
        if(Array.isArray(item)){
          arrs.push(... flatten(item))
        } else {
          arrs.push(item)
        }
      })
      return arrs
    }

字符串转换

arr.join(',').split(',').map(item => Number(item)))

使用Generator实现数组flatten:

function* flat(arr){
	for(let item of arr){
		if(Array.isArray(item)){
			yield* flat(item);//Generator委托
		}else {
			yield item
		}
	}
}
function flatten(arr) {
	let result = [];
	for(let val of(flat(arr))){
		result.push(val);
	}
	return result;
}
let arr1 = [1,[2,3,[4,5],6],[7]];
console.log(flatten(arr1));//[1, 2, 3, 4, 5, 6, 7]
const arr = [1,2,3,[4,5],6,[7,[8, 9, 10]]]

// 递归
function flatten(arr, res = []) {
    for (let i = 0; i < arr.length; i++) {
        if (typeof arr[i] === 'object') {
            flatten(arr[i], res);
        } else {
            res.push(arr[i]);
        }
    }
    return res;
}

// 队列
function flatten1(arr) {
    const newArr = [...arr];
    const res = [];
    while (newArr.length) {
        const item = newArr.shift(); // 出队
        if (Array.isArray(item)) {
            newArr.unshift(...item); // 入队
        } else {
            res.push(item);
        }
    }
    return res;
}

/**
*

  • @param {Array} arr 需要扁平化的数组
  • @param {Number} [depth=1] 扁平化深度
  • @return {Array} 扁平化后的新数组
    */
    function flatten(arr, depth = 1) {
    return arr.reduce((newArr, nextArr) => newArr.concat(depth > 1 && Array.isArray(nextArr) ? flatten(nextArr, depth - 1) : nextArr), [])
    }

ES10

arr.flat(Infinity);

function flatten(arr) {
  const result = [...arr];
  for (let i = 0; i < result.length; i++) {
    const item = result[i]
    if (Array.isArray(item)) {
      Array.prototype.splice.apply(result, [i, 1, ...item])
      i--
    }
  }
  return result
}
var arr=[1,2,3,[4,5],[6,[7,[8]]]]
function flatten(arr, result){
    if(!result){
        var result = [];
    }
    
    if(Object.prototype.toString.call(arr) == "[object Array]"){
        for (let i=0; i<arr.length; i++){
            if(Object.prototype.toString.call(arr[i]) == "[object Array]"){
                flatten(arr[i], result);
            }else{
                result.push(arr[i]);
            }
        } 
    }
    return result;
}

flatten(arr);
const flatten = (arr, deep) => {

    deep = deep ? deep : Infinity;
    while(deep && arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr);
        deep --;
    }
    return arr;
}
Array.prototype.flatten = function (deep) {
    
    return flatten(this, deep);
}
[1,[123,["213",["dorsey","123"]]]].flatten();
const flatten = x => x.reduce((pre, cur) => Array.isArray(cur) ? pre.concat(flatten(cur)) : pre.concat(cur), []);
let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]
arr.toString().split(',')
or
arr.join(',').split(',')

function flatten(a) {
return Array.isArray(a) ? [].concat(...a.map(flatten)) : a;
}

为什么我老是喜欢投机取巧,哈哈

var arr = [1,[2,3,[4,5]],8]
function flat (arr) {
  return JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']')
}
flat(arr)
const flatten = (arr) => {     
  if(Array.isArray(arr)) {
    return arr.reduce(((res, cur) => res.concat(flatten(cur))), [])
  }else {
    return [arr]
  }
}

为什么我老是喜欢投机取巧,哈哈

var arr = [1,[2,3,[4,5]],8]
function flat (arr) {
  return JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']')
}
flat(arr)

虽然不是考点,但也没啥不好的。😂

为什么我老是喜欢投机取巧,哈哈

var arr = [1,[2,3,[4,5]],8]
function flat (arr) {
  return JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']')
}
flat(arr)

虽然不是考点,但也没啥不好的。😂

这个怎么样😂

[1,[2,3,[4,5]],8].join(',').split(',').map(item => Number(item));
var arr = [1,[2,3,[4,5]],8]
function flatten(arr) {
   return arr.toString().split(",")
}
flatten(arr)
 ["1", "2", "3", "4", "5", "8"]

这样呢?

题目要求的是迭代的方式,各位取巧的同学。。。

function flatten(arr){
	let des = [];
	for(let i in arr){
		const v = arr[i];
		if(Array.isArray(v)){
			des = [...des,...flatten(v)]
			
		} else {
			des.push(v);
			
		}


	}
	return des;
	
}
function flatten(arr){
	let des = [...arr], i = 0;
	while(i <= des.length - 1) {
		if(Array.isArray(des[i])){
			des = [...des.slice(0, i), ...des[i], ...des.slice(i + 1, des.length)]
		} else {
			i++;
		}	
	}
	return des;
}

为什么我老是喜欢投机取巧,哈哈

var arr = [1,[2,3,[4,5]],8]
function flat (arr) {
  return JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']')
}
flat(arr)

虽然不是考点,但也没啥不好的。😂

这个怎么样😂

[1,[2,3,[4,5]],8].join(',').split(',').map(item => Number(item));

[1,[2,3,[4,5]],8].toString().split(",").map(Number)

// reduce
function flatten(arr) {
    return arr.reduce((total, item) => total.concat(Array.isArray(item) ? flatten(item) : [item]), [])
}
// map
function flatten(arr) {
    return [].concat(...arr.map(item => Array.isArray(item) ? flatten(item) : item))
}
// for
function flatten(arr, result = []) {
    for (let item of arr) {
        if (Array.isArray(item)) {
            flatten(item, result)
        } else {
            result.push(item)
        }
    }
    return result
}
function flattern(list) {
  const stack = [...list]
  const des = []
  while (stack.length) {
    const next = stack.pop()
    if (Array.isArray(next)) {
      stack.push(...next)
    } else {
      des.push(next)
    }
  }
  return des.reverse()
}
var arr=[1,2,3,[4,5],[6,[7,[8]]]]
/**
 * 使用递归的方式处理
 * wrap内保存结果ret 
 * 返回一个递归函数
 *
 * @returns
 */
function wrap(){
    var ret=[];
    return function flat(a){
        for(var item of a){
            if(item.constructor===Array){
                ret.concat(flat(item))
            }else{
                ret.push(item)
            }
        }
        return ret
    }
}
console.log(wrap()(arr));

将一个多维数组拍平为一个一维数组

ret = ret.concat(flat(item))

function flatten(arr, temp = []){
  arr.forEach((item) => {
   if(Array.isArray(item)) {
    flatten(item, temp)
   } else {
    temp.push(item)
   }
  })
  return temp
}
function flatten(arr) {
  if (!Array.isArray(arr) || !arr.length) return [];
  
  const tempArr = []; // 辅助数组
  const result = []; // 用来保存结果

  tempArr.push([arr, 0]);

  while (tempArr.length) {
    const currentArr = tempArr[tempArr.length - 1];
    const [current, index] = currentArr;

    if (index >= current.length) {
      tempArr.pop();
      continue;
    }

    currentArr[1]++; // 下标 + 1

    const currentItem = current[index];
    if (Array.isArray(currentItem)) {
      tempArr.push([currentItem, 0]);
      continue;
    }

    result.push(currentItem);
  }

  return result;
}

function flatten(arr,result){ for(let item of arr){ if(Array.isArray(item)){ ...flatten(item,result) }else{ result.push(item) } } }

let attr=[1,2,3,[4,5],[6,[7,[8]]]];
   function flatten(attr){
     if(Array.isArray(attr)){
       let att=[]
        for (let item of attr){
          att=  att.concat(flatten(item))
        }
        return att
     }
     else {
       return attr
     }
   }
flatten (attr)
// O(n)
const flat = function(array) {
  let tail = []
  let index = 0
  while (0 < array.length) {
    let elem = array.pop()
    if (Array.isArray(elem)) {
      array.push(...elem)
    } else {
      tail.push(elem)
    }
  }
  return tail.reverse()
}

const nestedArray = [[[1,2],3,[4,[5,6]],7,8],9]
console.log(nestedArray)
console.log(flat(nestedArray))
function flatten (arr) {
    if (arr.length <=1) return arr;
    const flatArr = [];
    for (let i = 0; i<arr.length; i++) {
        if(Object.prototype.toString.call(arr[i]) == '[object Array]') {
              flatArr = flatArr.concat(flatten(arr[i]))
        } else {
              flatArr.push(arr[i])
        }
    }
    return flatArr
}

let test = [[[1,2,3], 4], 5]
console.log(flatten(test))

迭代

const flatten = (arr, list = []) => {
  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      arr = arr.slice(0, i).concat(arr[i]).concat(arr.slice(i + 1))
      i--
    } else {
      list.push(arr[i])
    }
  }
  return list
}

递归

const flat = (arr, list = []) => {
  if (!Array.isArray(arr)) return list.push(arr)
  arr.forEach(item => flat(item, list))
  return list
}
var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];

function flattenDeep(arr1) {
   return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
}
flattenDeep(arr1);
//我的最"笨"的迭代方法
function flat_arr(arr,new_arr){
	for(let i=0;i<arr.length;i++){
		let item=arr[i];
		if(Array.isArray(item)){
			 flat_arr(item,new_arr);
		}else{
			new_arr.push(item)
		}
		
  }
}

var arr=[1,2,3,[4,5],[6,[7,[8]]]]

var new_arr=[];

flat_arr(arr,new_arr)
console.log(new_arr)

ES6的flat函数

var arr=[1,2,3,[4,5],[6,[7,[8]]]]
arr.flat(Infinity);

迭代的实现:

let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]

const flatten = function (arr) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr)
    }
    return arr
}

console.log(flatten(arr))

递归的实现(ES6简写):

const flatten = array => array.reduce((acc, cur) => (Array.isArray(cur) ? [...acc, ...flatten(cur)] : [...acc, cur]), [])

很棒的思路,Array.some那句有点冗余,可以这样写
const flatten = function (arr) {
while (arr.some(Array.isArray)) {
arr = [].concat(...arr)
}
return arr
}

迭代的实现:

let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]

const flatten = function (arr) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr)
    }
    return arr
}

console.log(flatten(arr))

递归的实现(ES6简写):

const flatten = array => array.reduce((acc, cur) => (Array.isArray(cur) ? [...acc, ...flatten(cur)] : [...acc, cur]), [])

使用 some 判断 怎么会一遍一遍把 arr 扩展吗?有谁可以解释下吗?

  function flattern(arr) {
      var result = []
      arr.forEach(item => {
        result = Array.isArray(item) ? result.concat(flattern(item))  :result.concat(item)
      })
      return result
    }
function flatten(arr){
  return arr.reduce(function(pre, cur){
    if(Array.isArray(cur)){
      return pre.concat(flatten(cur))
    } else {
      return pre.concat(cur)
    }
  }, [])
}
var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];
function flatten(input) {
  const stack = [...input];
  const res = [];
  while (stack.length) {
    // 使用 pop 从 stack 中取出并移除值
    const next = stack.pop();
    if (Array.isArray(next)) {
      // 使用 push 送回内层数组中的元素,不会改动原始输入 original input
      stack.push(...next);
    } else {
      res.push(next);
    }
  }
  // 使用 reverse 恢复原数组的顺序
  return res.reverse();
}
flatten(arr1);// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]

一行代码:

const flatten = arr => arr.some(item => Array.isArray(item)) ? flatten([].concat(...arr)) : arr;

const flatten = arr => arr.reduce((acc, cur) => (Array.isArray(cur) ? [...acc, ...flatten(cur)] : [...acc, cur]), []);
function flatten(arr) {
  var res = arr;
  var i = 0;
  while (i < res.length) {
    if (Array.isArray(res[i])) {
      res.splice(i, 1, ...res[i]);
    }
    i++;
  }
  console.log(res);
  return res;
} 

flatten([1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, [13, 14, [15, 16]]]]]);

不断迭代,遇到数组的元素,用该数组的解构替换该元素,这样就改变了原数组的长度,继续迭代,进行这种判断和处理。

const flatten = Function.apply.bind([].concat,[])

迭代的实现:

let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]

const flatten = function (arr) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr)
    }
    return arr
}

console.log(flatten(arr))

递归的实现(ES6简写):

const flatten = array => array.reduce((acc, cur) => (Array.isArray(cur) ? [...acc, ...flatten(cur)] : [...acc, cur]), [])

牛逼啊,老哥

递归写法

function flatten(arr) {
  let result = []
  for(let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      result = result.concat(flatten(arr[i]))
    } else {
      result.push(arr[i])
    }
  }
  return result
}

toString 「存在限制,对于存在多种类型的数组无法使用」

因为元素的数组都是数字 多层数组直接调用 toString会返回一个扁平的逗号分隔的字符串

[1,[2,[3,4]]].toString() // "1,2,3,4"

所以我们通过先转化成扁平字符串在转化为数字数组实现扁平化

function flatten(arr) {
  return arr.toString().split(',').map(item => +item)
}

reduce

使用数组的reduce累加方法

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

ES6扩展运算符

扩展运算符可以取出参数对象的可遍历属性,拷贝到当前对象之中

var arr = [1, [2, [3, 4]]];
console.log([].concat(...arr)); // [1, 2, [3, 4]]

但一次扩展运算符只能展开一层 我们可以添加循环条件

function flatten(arr) {
  while(arr.some(item => Array.isArray(item))) {
    arr = [].concat(...arr)
  }
  return arr
}

同时我们可以设置出展开特定层数的方法

function flatten(arr, count) {
  while (arr.some(item => Array.isArray(item) && count-- > 0)) {
    arr = [].concat(...arr)
  }
  return arr
}

Generator函数

我们可以使用Generator函数来展开多重数组

function *flatten(arr) {
  for(const item of arr) {
    if (Array.isArray(item)) {
      yield *flatten(item)
    } else {
      yield item
    }
  }
}

const flattened = [...flatten([1,2,[3,4,[5,6]]])];  // [1,2,3,4,5,6]
1. array.reduce
function flattenDeep(ary) {
   return Array.isArray(ary) ? ary.reduce((a,b) => [...a,...flattenDeep(b)],[]) : [ary];
}

2. generator
function* demo(ary) {
        for (let i = 0; i < ary.length; i++) {
            if (Array.isArray(ary[i])) {
                yield* demo(ary[i]);
            } else {
                yield ary[i];
            }
        }
    }
    for (let f of demo(ary)) {
        console.log(f);
    }
wxmac commented

1.使用栈的**实现 flat 函数
const flat = (arr) => { const stack = [...arr]; const res = []; while( stack.length ){ const next = stack.pop(); if(Array.isArray(next)){ stack.push(...next); } else { res.push(next) } } return res.reverse(); };

2.reduce + 递归

const flat = (arr) => { return arr.reduce((prv,cur) => { return Array.isArray(cur) ? prv.concat(flat(cur)) : prv.concat(cur) },[]) }

function flatten(arr) {
  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      arr = arr.concat(arr[i])
      arr.splice(i, 1)
    }
  }
  return arr;
}

let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]

console.log(flatten(arr))

let test = [1, 2, [3, 4, 5,[6,7]]];
Array.prototype.myFlat = function () {
const result = [];
this.forEach(item => {
if ((typeof item) !== 'object') {
result.push(item);
} else {
result.push(...Array.prototype.myFlat.apply(item));
}
});
return result;
};
console.log(test.myFlat());

Array.reduce()

// 数组调用recduce方法时,可以传递两个参数,第一个参数为回调函数,第二个参数为一个初始值。
// 回调函数中需要传递两个参数,第一个参数为每次执行函数的返回值,第二个参数为当前索引对应数组的值。
// reduce的第二个参数是可以省略的,省略的话,回调函数第一次调用的参数为数组的第一项和第二项的值,
// 如果没有省略,回调函数的第一个参数就是这个初始值。
function flatten (arr) {
    return arr.reduce((prev, curr) => {
        return Array.isArray(curr) ? [...prev, ...flatten(curr)] : [...prev, curr]
    }, [])
}
    栈的写法
let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]
function flat(arr) {
	let stack = []
	let newArr = []
	stack.push(arr)
	while (stack.length) {
		let item = stack.pop()
		if (item.length) {
			for (let i = item.length-1; i >-1; i--) {
				stack.push(item[i])
			}
		} else {
			newArr.push(item)
		}

	}
	return newArr
}
console.log(flat(arr));
var arr = [1,[2,3,[4,5]],8]
function flatten(arr) {
   return arr.toString().split(",")
}
flatten(arr)
 ["1", "2", "3", "4", "5", "8"]

这样呢?

应该让元素保持number类型, flatten(arr).map(Number)

Iterator 版:

const getIterator = (iteratorable) => iteratorable[Symbol.iterator]()

const getDataType = (data) => Object.prototype.toString.call(data).slice(8,-1)

const isArray = (data) => getDataType(data) === 'Array'

const flatten = (arr,deep=1) => {

  const flatArr = []

  const iteratorFn = (array,dep) => {
    const iterator = getIterator(array)

    while(true){
      const obj = iterator.next()
      if(obj.done){
        break;
      }
      if(isArray(obj.value)&&dep>0){
        dep--
        iteratorFn(obj.value, dep)
      }else{
        flatArr.push(obj.value)
      }
    }
  }
  iteratorFn(arr,deep)
  return flatArr
}
const arr = [1 ,[ 2,3,[4,5,6,[7,8,9,10]]]]

test:

const arr = [1 ,[ 2,3,[4,5,6,[7,8,9,10]]]]
flatten(arr)
// [1, 2, 3, Array(4)]
flatten(arr,2)
// [1, 2, 3, 4, 5, 6, Array(4)]
flatten(arr,3)
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

迭代的实现:

let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]

const flatten = function (arr) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr)
    }
    return arr
}

console.log(flatten(arr))

递归的实现(ES6简写):

const flatten = array => array.reduce((acc, cur) => (Array.isArray(cur) ? [...acc, ...flatten(cur)] : [...acc, cur]), [])

使用 reduce 也属于迭代吧?

递归
var flatten = (arr) => arr.every(ele => ele?.constructor !== Array) ? arr : flatten([].concat(...arr))

tjwyz commented
function flat(arr) {
	let ret = [];
	arr.forEach(item => {
		if (+item === item) {
			ret.push(item);
		} else {
			ret = ret.concat(flat(item));
		}
	})
	return ret;
}

队列方式:

function flatten(arr) {
  const ret = [];
  const queue = [];
  let index = 0;

  while (index < arr.length || queue.length) {
    // 取出 queue中的元素然后处理
    const queueLen = queue.length;
    for (let i = 0; i < queueLen; i++) {
      const item = queue.shift();
      if (Array.isArray(item)) {
        for (let j = 0; j < item.length; j++) {
          queue.push(item[j]);
        }
      } else {
        ret.push(item);
      }
    }
    // 取出原数组放入queue
    if (index < arr.length) queue.push(arr[index++]);
  }
  return ret;
}

var arr=[1,2,3,[4,5],[6,[7,[8]]]]

function getArr(arr) {

let result=[]

for (let i = 0; i < arr.length; i++) {
    const element = arr[i];
    if(element instanceof Array) {
       result = [...result,...getArr(element)]
    }
    else {
        result.push(element)
    }
}
return result;

}

console.log(getArr(arr))

function flatten(arr) {
  if (!arr.length) {
    return []
  }
  let stack = [...arr]
  let res = []
  while (stack.length) {
    let item = stack.pop()
    if (Array.isArray(item)) {
      for (let cld of item) {
        stack.push(cld)
      }
    } else {
      res.unshift(item)
    }
  }
  return res
}
var arr=[1,2,3,[4,5],[6,[7,[8]]]];
function flatten(arr = []){
    const newArr = [];
    while(arr.length > 0){
        const first = arr.shift();
        if(Array.isArray(first)){
            arr = [...first, ...arr];
        }else {
            newArr.push(first);
        }
    }
    return newArr;
}
console.log(flatten(arr));//  [1, 2, 3, 4, 5, 6, 7, 8]

用reduce来实现

let a= [[1,2,[3]],[4,5,[6,[[7],8]],9]]
const flatten = (arr) => {
    return arr.reduce((pre, item) => {
        return pre.concat(Array.isArray(item) ? flatten(item) : item)
    },[])
}
console.log(flatten(a))

迭代实现

function flatten(arr) {
  const result = []
  let target = arr

  while (Array.isArray(target)) {
    const copy = target.slice()
    for (let i = 0; i < copy.length; i += 1) {
      target = copy[i]
      if (!Array.isArray(copy[i])) {
        result.push(copy[i])
      }
    }
  }
  return result
}

递归实现

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

String(arr).split(',').map(Number)

const a = [1,2,3,[4,5,6,[7,8]]]

// 递归
const flatten = (arr) => {
  return arr.reduce((sum,curr) => {
    return sum.concat(Array.isArray(curr) ? flatten(curr) : curr);
  },[])
}

// 迭代
const iterativeFlatten = (arr) => {
  const stack = [];
  const rlt = [];
  stack.push(arr);
  while(stack.length){
    while(Array.isArray(stack[stack.length - 1])){
      const temp = stack.pop();
      for(let i = temp.length-1; i>=0; i++){
        stack.push(temp[i]);
      }
    }
    rlt.push(stack.pop());
  }
  return rlt;
}

三种方式

//  toString()
var flatten = (arr) => {
  return arr.toString().split(',').map(Number)
}

// 递归
var flatten = (arr) => {
  var ret = []
  arr.forEach(item => {
    var temp = Array.isArray(item) ? flatten(item) : [item]
    ret.push(...temp)
  })
  return ret
} 

// 迭代
var flatten = (arr) => {
  if(!arr.length) {
    return []
  }

  var ret = []
  var queue = [arr]
  while(queue.length) {
    var cur = queue.shift()
    if (Array.isArray(cur)) {
      queue.unshift(...cur)
    } else {
      ret.push(cur)
    }
  }
  
  return ret
} 
function flatten(arr) {
    const items = [].concat(arr) // 拷贝数组防止直接操作原数组
    const res = [] // 创建新的数组
    while (items.length) { // 如果拷贝的数组还有数据
        const item = items.shift() // 弹出第一个数据
        if (Array.isArray(item)) { // 如果弹出的是一个数组
            items.unshift(...item) // 那么推入
        } else { 
            res.push(item) // 推入返回的数组
        }
    }
    return res
}

使用栈将element反复推入拍平数组

let flatten = arr => {
    const newArr = [];
    let cur = null;
    while(cur = arr.pop()) {
        if (Array.isArray(cur)) {
            arr.push(...cur)
        } else {
            newArr.push(cur)
        }
    }
    return newArr.reverse()
}

ES6实现无限层级的flatten

const flatten = arr => arr.reduce((acc, cur) => (
    Array.isArray(cur) 
   ? [...acc, ...flatten(cur)]
   : [...acc, cur]
), []);

进一步优化一下,带有depth参数

const flattenBydepth = (arr, depth = 1) => 
    depth > 1
        ? arr.reduce((acc, cur) => Array.isArray(cur) 
            ? [...acc, ...flattenBydepth(cur, depth -1)] 
            : [...acc, cur], [])
        : arr.reduce((acc, cur) => [...acc, cur], []);

惭愧这么个简单的功能居然写了快50行。。。不过带上了对depth的处理,抛砖引玉吧

const iterationFlatten = (arr,depth=1)=>{
    if (!Array.isArray(arr)) {
        return [];
    }

    if (depth <= 0) {
        depth = 1;
    }

    // 存放结果
    const result = [];
    // 当前迭代深度
    let currentDepth = 0;
    // 对应深度中,当前进行迭代的索引(因为能够进行迭代的必然是数组)
    const layerIterationIndex = [0];
    // 对应深度中,当前正在进行迭代的数组对象
    let targetStack = new Array();

    targetStack.push(arr);

    while (layerIterationIndex[0] !== arr.length) {
        // 本次迭代的元素所在的数组
        const layerElement = targetStack[currentDepth];
        // 本次迭代的元素 
        const target = layerElement[layerIterationIndex[currentDepth]];
        // 本层迭代是否应该继续(数组已经迭代完毕,或者当前深度超出depth指定的值)
        const endOfThisLayer = (layerIterationIndex[currentDepth] === (layerElement.length)) || (currentDepth > depth);

        if (endOfThisLayer) {
            // 如果超出depth指定的值,则将本层元素直接放进结果            
            if (currentDepth > depth) {
                result.push(layerElement);
            }

            // 层数-1 上层迭代索引+1(因为上一层迭代中,本元素已经迭代完毕)
            currentDepth--;
            layerIterationIndex[currentDepth]++;
            
            // 弹出本层迭代元素,以及迭代索引
            layerIterationIndex.pop();
            targetStack.pop();
        } else {
            // 如果本次迭代的元素是数组,则以本元素进行深一层迭代,将本此迭代元素入栈,迭代索引入栈,初始化为0
            if (Array.isArray(target)) {
                targetStack.push(target);
                currentDepth++;
                layerIterationIndex.push(0);
            } else {
                // 如果不是数组,则直接放入结果数组,并且本层迭代索引+1
                result.push(target);
                layerIterationIndex[currentDepth]++;
            }
        }
    }

    return result;
}

// (5) [1, 2, 3, 4, Array(3)]
console.log(iterationFlatten([1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]]))
// (7) [1, 2, 3, 4, 5, 6, Array(3)]
console.log(iterationFlatten([1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]], 2))
// (10) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(iterationFlatten([1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]], Infinity))

``function myflatten(arr, deep) {
let result = [];
let temp1 = arr;//当前用来遍历的数组
let temp2 = [];//保存下一次用来遍历的数组

    while (deep) {
        //如果元素是数组就放到temp2里面去,不是就放到result里
        for (let i = 0; i < temp1.length; i++) {
            if (temp1[i] instanceof Array) {
                temp2.push(...temp1[i]);
            } else {
                result.push(temp1[i]);
            }
        }
        deep--;
        //到达深度后要把没遍历的数组放到result里
        if (deep == 0) {
            result.push(...temp2);
        } else {
        temp1 = temp2;
        temp2 = [];
    }
}
return result;`

//应该是迭代次数较少,而且比较方便的方法
function flatten(arr) {
if(!(arr instanceof Array)){
return
}
var result = [], temp = [],head;
if(arr.length <= 0) {
return result;
}
temp.push(arr);
while (temp.length) {
head = temp.shift();
//元素是数组
if (head instanceof Array) {
for (let i = 0; i < head.length; i++) {
if (!(head[i] instanceof Array)) {
result.push(head[i]);
} else {
temp.push(head[i])
}
}
} else {
result.push(head)
}
}
return result;
}

迭代的实现:

let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]

const flatten = function (arr) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr)
    }
    return arr
}

console.log(flatten(arr))

递归的实现(ES6简写):

const flatten = array => array.reduce((acc, cur) => (Array.isArray(cur) ? [...acc, ...flatten(cur)] : [...acc, cur]), [])

卧槽concat居然有这功能,只写过拼数组,单个元素也能拼厉害了, [ ].concat(1,2,[3]) == [1,2,3]

chiic commented
function flatten(arr) {
    let i = 0;
    while(i < arr.length) {
        if(Array.isArray(arr[i])) {
            var len = arr[i].length;
            arr.splice(i, 1, ...arr[i]);
        } else {
            i++;
        }
    }
    return arr;
}
function flat(target) {
  let arr = [];
  target.forEach((element) => {
    if (Array.isArray(element)) arr.push(...flat(element));
    else arr.push(element);
  });
  return arr;
}
let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]];
console.log("结果", flat(arr));

var arr=[1,2,3,[4,5],[6,[7,[8]]]]
function flatten(arr){
return arr.reduce((pre,cur)=>{
return pre.concat(Array.isArray(cur)?flatten(cur):cur)
},[])
}
var newArr = flatten(arr)
console.log(newArr) // [1,2,3,4,5,6,7,8]

迭代啊,不要用递归。

迭代的实现:

let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]

const flatten = function (arr) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr)
    }
    return arr
}

console.log(flatten(arr))

递归的实现(ES6简写):

const flatten = array => array.reduce((acc, cur) => (Array.isArray(cur) ? [...acc, ...flatten(cur)] : [...acc, cur]), [])

使用 reduce 也属于迭代吧?

recude内调用flatten自身

从语义的角度,递归实现是否用forEach更好,另reduce实现:

function flatten(arr) {
  return arr.reduce((acc, cur) => {
    if(Array.isArray(cur)) {
      acc.push(...flatten(cur))
    } else {
      acc.push(cur)
    }

    return acc
  }, [])
}

从语义的角度,递归实现是否用forEach更好,另reduce实现:

function flatten(arr) {
  return arr.reduce((acc, cur) => {
    if(Array.isArray(cur)) {
      acc.push(...flatten(cur))
    } else {
      acc.push(cur)
    }

    return acc
  }, [])
}
// 返回数组的维数(虽然没用到)
function arrDimension(arr) {
  return arr.length ? Math.max(...arr.map(item => Array.isArray(item) ? arrDimension(item) + 1 : 1)) : 1
}

function flatten(arr, depth = 1) {
  if(depth === 0) return arr

  return arr.reduce((acc, cur) => {
    if(Array.isArray(cur)) {
      acc.push(...flatten(cur, depth - 1))
    } else {
      acc.push(cur)
    }

    return acc
  }, [])
}
const flattenRecursion = (itemList, resList) => {
    itemList.forEach(item => {
        if (Array.isArray(item)) {
            flattenFormat(item, resList);
            return;
        }

        resList.push(item);
    })

    return resList;
}

const flattenIterate = itemList => {
    const flattenedList = [];

    while(itemList.length > 0) {
        let head = itemList.shift();
        if (Array.isArray(head)) {
            itemList.unshift(...head);
        } else {
            flattenedList.push(head);
        }
    }

    return flattenedList;
}



const arr = [1,2,3,[4,5],[6,[7,[8]]]];

const flattenedList = flattenIterate(arr, []);
console.log(flattenedList);
function reduceFlat(arr = []) {
  return arr.reduce((res, item) => res.concat(Array.isArray(item) ? reduceFlat(item) : item), [])
}
reduceFlat([1,2,3,[4,5],[6,[7,[8]]]])
// [1, 2, 3, 4, 5, 6, 7, 8]
XW666 commented
const flatten2 = (arr) => {
    let list = []
    //递归方式
    let fun = (data) => {
      for (let c of data) {
        if (Array.isArray(c)) {
          fun(c)
        } else {
          list.push(c)
        }
      }
    }
    fun(arr)
    console.log('flatten2', list)
  }
  flatten2([1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]])