BetaSu / fe-hunter

每天一道题,3个月后,你就是面试小能手,答题还能赚钱哦
1.67k stars 116 forks source link

实现数组扁平化 #34

Closed BetaSu closed 2 years ago

BetaSu commented 2 years ago

要实现的功能

在 JavaScript 中实现拍平数组,你有几种方法?

代码示例

// 给你一个数组:[1, [2, 3, [4], 5], 6]
// 你需要输出: [1, 2, 3, 4, 5, 6]

最佳答案评选标准

  1. 如果给出多种解决方案,请简要阐明他们的优劣
  2. 请写出实现思路、代码,并为代码的关键步骤增写注释
  3. 附带测试用例、是加分项
  4. 不需要考虑异常发生
  5. 不过度设计,代码简洁优雅是加分项

最佳答案

childrentime的回答

答题同学须知

围观同学须知

shabbyaaa commented 2 years ago

直接使用ES6的方法flat

Chorer commented 2 years ago

二维数组

// 方法一
function flat(arr){
    const res = []
    for(let i=0;i<arr.length;i++){
        if(Array.isArray(arr[i])){
            for(let j=0;j<arr[i].length;j++){
                res.push(arr[i][j])
            }
        } else {
            res.push(arr[i])
        }
    }
}

// 方法二
function flat(arr){
    const res = []
    for(x of arr){
        res.concat(x)
    }
    return res
}

// 方法三
arr.reduce((acc,cur) => acc.concat(cur),[])

// 方法四
[].concat(...arr)

// 方法五
[].concat.apply(null,arr)

多维数组

// 方法一
function flat(arr,res = []){
    arr.forEach(item => {
        Array.isArray(item) ? flat(item,res): res.push(item)
    })
    return res
}

// 方法二
function flat(arr){
    return arr.reduce((acc,cur) => {
        return Array.isArray(cur) ? acc.concat(flat(cur)) : acc.concat(cur)
    },[])
}

// 方法三
function flat(arr){
    while(arr.some(item => Array.isArray(item))){
        arr = [].concat(...arr)
    }
    return arr
}

// 方法四(要求所有元素数据类型相同,以数字型数组为例)
function flat_numberArray(arr){
    return arr.toString().split(',').map(x => Number(x))
}
nonzzz commented 2 years ago

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

const { isArray } = Array

const flatten = (arr) =>
  arr.reduce((acc, cur) => {
    return acc.concat(isArray(cur) ? flatten(cur) : cur)
  }, [])

const _arr = flatten(arr)

console.log(_arr) // [ 1, 2, 3, 4, 5, 6 ]

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

const len = (arr) => arr.length

const { isArray } = Array

const flatten = (arr) => {
  const stack = [...arr]
  const res = []
  while (len(stack)) {
    const f = stack.shift()
    if (isArray(f)) {
      stack.unshift(...f)
    } else {
      res.push(f)
    }
  }
  return res
}

const _arr = flatten(arr)

console.log(_arr)
codekeqiong commented 2 years ago

// 实现方式一:reduce const flatten = arr => arr.reduce((res, cur) => res.concat(Array.isArray(cur) ? flatten(cur) : cur), []);

// 实现方式二:tostring const flatten2 = arr => arr.toString().split(',').map(item => Number(item));

// 实现方式三:join const flatten3 = arr => arr.join().split(',').map(item => Number(item));

// 实现方式四:flat(Infinity) const flatten4 = arr => arr.flat(Infinity);

// 实现方式五:正则 const flatten5 = arr => JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g,'') + ']');

// 实现方式六:扩展运算符

const flatten6 = arr => {
  while (arr.some(item => Array.isArray(item))) {
    arr = [].concat(...arr);
  }
  return arr;
};
xl9-7 commented 2 years ago

arr.flat(Infinity)

vfiee commented 2 years ago

ES6原生支持Array.prototype.flat

// 之前写的,直接拿来用一下

// 判断是否为数组
const isArray = Array.isArray

// 减少一级数组的嵌套深度
const flatten = (array) => flattenDepth(array)

// 深层次扁平化数组
const flattenDeep = (array) => flattenDepth(array, Infinity)

// 根据用户层级扁平化数组,默认一层
const flattenDepth = (array, depth = 1) => {
   // 如果不是数组,返回传入的参数
    if (!isArray(array)) return array
   // 定义当前扁平化层级
    let current = 0
    const flat = (array, depth, currentDepth) => {
        // 声明 result,作为结果返回
        let result = []
        // 遍历数组
        for (const item of array) {
           // 如果是数组且遍历深度不大于指定深度, 继续扁平化
            if (isArray(item) && currentDepth + 1 <= depth) {
                result.push(...flat(item, depth, currentDepth + 1))
            } else {
                // 否则,插入结果
                result.push(item)
            }
        }
        // 返回结果
        return result
    }
    return flat(array, depth, current)
}
// 测试
// 一维
const test1 = () => {
    const array = [1, 2, 3]
    console.log(`flatten1:`, flatten(array)) // flatten1: (3) [1, 2, 3]
    console.log(`flattenDeep1:`, flattenDeep(array)) // flattenDeep1: (3) [1, 2, 3]
}

// 二维
const test2 = () => {
    const array = [[1], [2], [3]]
    console.log(`flatten2:`, flatten(array)) // flatten2: (3) [1, 2, 3]
    console.log(`flattenDeep2:`, flattenDeep(array)) // flattenDeep2: (3) [1, 2, 3]
}

// 三维
const test3 = () => {
    const array = [[[1]], [[2]], [[3]]]
    console.log(`flatten3:`, flatten(array)) // flatten3: (3) [Array(1), Array(1), Array(1)]
    console.log(`flattenDeep3:`, flattenDeep(array)) // flattenDeep3: (3) [1, 2, 3]
}

// 多维
const test4 = () => {
    const array = [[[[1]]], [[[2]]], [[[3]]]]
    console.log(`flatten:`, flatten(array)) // flatten4: (3) [Array(1), Array(1), Array(1)] 粘的浏览器打印结果,无法展开
    console.log(`flattenDeep:`, flattenDeep(array)) // flattenDeep4: (3) [1, 2, 3] 
}
const runTest = () => {
    test1()
    test2()
    test3()
    test4()
}

runTest()
fightZy commented 2 years ago

代码

测试

let arr = [1, [2, 3, [4], 5], 6]

console.log(fn1(arr));
console.log(fn2(arr));
console.log(fn3(arr));
console.log(fn4(arr));
console.log(fn5(arr));

输出: image

Alexlangl commented 2 years ago

可以分情况进行讨论 arr为我们需要扁平的数组

示例中使用箭头函数,要求node版本至少大于4.0.0,可以使用function方式定义flatten方法 示例中使用的spread运算符,要求node版本至少大于5.0.0,当node版本小于5.0.0时,可以使用其它方法实现

如果数组为n为数组,且node版本大于11.0.0

a. 已经知数组维度为n:

arr = arr.flat(n)

b.未知数组维度:

arr = arr.flat(Infinity)

c. n为2

arr.flatMap(el => el)

如果数组为n维数组,且node版本小于11.0.0

a. stack

const flatten = (arr) => {
  // copy数组
  const stackArr = [...arr]; 
  const res = [];
  while (stackArr.length) {
    const part = stackArr.shift();
    if (Array.isArray(part)) {
      stackArr.unshift(...part);
    } else {
      res.push(part);
    }
  }
  return res;
}

b. for循环

const flatten = (arr) => {
  var res = [];
  for (let i = 0, length = arr.length; i < length; i++) {
    if (Array.isArray(arr[i])) {
      res.push(...flatten(arr[i]));
    } else {
      res.push(arr[i]);
    }
  }
  return res;
}

c. reduce

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

这里的reset运算符的使用可以替换成concat方法

d. while

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

同样的,这里的reset运算符也可以使用concat方法

e. 翻版递归

yield需要node版本大于4.0.0

function* flatten(arr) {
for (const el of arr) {
if(Array.isArray(el)){
yield* flatten(el)
} else {
yield el
}
}
}
const newArr = [...flatten(arr)]

数组为纯数字数组,且n维

const flatten = (arr) => {
return arr.toString().split(',').map(el => {
return +el
})
}
childrentime commented 2 years ago

ES6

arr.flat(Infinity);

数组中全为数字

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

递归

const myFlat = (arr) => {
  const helper = (arr) => {
    let res = [];
    for (const item of arr) {
      if (typeof item === 'object') {
        res.push(...item);
      } else {
        res.push(item);
      }
    }
    return res;
  };

  while (arr.some(item => typeof item === 'object')) {
    arr = helper(arr);
  }
  return arr;
};

栈代替递归

const myFlat1 = (input) => {
  const stack = [...input];
  const res = [];
  while (stack.length) {
    const next = stack.pop();
    if (Array.isArray(next)) {
      stack.push(...next);
    } else {
      res.push(next);
    }
  }
  return res.reverse();
};

正则过滤

function myFlat3(arr) {
  let str = JSON.stringify(arr);
  // 过滤所有的中中括号
  str = str.replace(/(\[|\])/g, '');
  str = '[' + str + ']';
  return JSON.parse(str);
}

生成器

function* myFlat2(array, depth = 1) {
  for (const item of array) {
    if (Array.isArray(item) && depth > 0) {
      yield* myFlat2(item, depth - 1);
    } else {
      yield item;
    }
  }
}
houhaizimen commented 2 years ago

const s = [1, [2, 3, [4], 5], 6] // 函数体 function flatList (list, resList) { resList = resList || [] for (let value of list) { if (Array.isArray(value)) { flatList(value, resList) } else { resList[resList.length] = value } } return resList } // 验证 console.log(flatList(s))