js 实现数组扁平化

数组扁平化即将多层级数组转化成一层数组。

如: 

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

我们需要实现的就是flatten方法。

1.利用ES6的flat方法

ES6中数组新增了flat方法,会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。

其中参数表示想要拉平的层数,默认为1。如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。

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

arr.flat();    // [1, 2, 3, [4, 5, [6]]]

arr.flat(2);    // [1, 2, 3, 4, 5, [6]]

arr.flat(Infinity);   // [1, 2, 3, 4, 5, 6]
// 使用 Infinity,可展开任意深度的嵌套数组

var arr1 = [1, 2, , 4, 5];
// 会将empty元素过滤掉
arr1.flat();  // [1, 2, 4, 5]

2. 使用reduce + concat + 递归

var arr=[1,2,[3, 4, [5,6,[7]]]];
function flatten(arr, deep){
    return deep > 1 ? arr.reduce((prev, next) => prev.concat(Array.isArray(next) ? flatten(next, deep - 1) : next), []) : arr.slice()
}
flatten(arr, Infinity);

3.利用栈/队列 + 拓展运算符

// 也可以使用shift/unshift, 但使用pop/push速度更快
function flatten(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();
}

利用队列 

// 使用shift/unshift
function flatten1(input) {
  const stack = [...input];
  const res = [];
  while (stack.length) {
    const next = stack.shift();
    if (Array.isArray(next)) {
      stack.unshift(...next);
    } else {
      res.push(next);
    }
  }
  return res;
}

 测试下:

// 创建整数灵活编号的列表
function range(start, stop, step) {
  if (stop == null) {
    stop = start || 0;
    start = 0;
  }
  if (!step) {
    step = stop < start ? -1 : 1;
  }

  var length = Math.max(Math.ceil((stop - start) / step), 0);
  var range = Array(length);

  for (var idx = 0; idx < length; idx++, start += step) {
    range[idx] = start;
  }

  return range;
}


var arr = range(10000);
// 需要扁平化的数组
var list = [arr, [arr], [arr, [arr]]]

console.time('使用pop/push耗时');
flatten(list)
console.timeEnd('使用pop/push耗时');


console.time('使用shift/unshift耗时');
flatten1(list)
console.timeEnd('使用shift/unshift耗时');

或使用

var arr=[1,2,[3, 4, [5,6,[7]]]];
function flatten(arr){
    while(arr.some(Array.isArray)){
        arr = [].concat(...arr)
    }
    return arr;
}

4. 使用Generator函数

function* flatten(array, depth) {
  if (depth === undefined) {
    depth = 1;
  }

  for (const item of array) {
    if (Array.isArray(item) && depth > 0) {
      yield* flatten(item, depth - 1);
    } else {
      yield item;
    }
  }
}

const arr = [1, 2, [3, 4, [5, 6]]];
const flattened = [...flatten(arr, Infinity)];
// [1, 2, 3, 4, 5, 6]

5.使用toString + split方法(只适用于都是数字组成的数组)

var arr=[1,2,[3, 4, [5,6,[7]]]];
function flatten(arr){
    return arr.toString().split(',').map(item => +item);
}
console.log(flatten(arr));

这种方法使用场景有限,如果数组是[1, '1', 2, '2']就会出问题,只适用于都是数字组成的数组

6. 正则(不推荐)

function flatten(arr) {
  let str = JSON.stringify(arr);
  str = str.replace(/(\[|\])/g, '');
  str = '[' + str + ']';
  return JSON.parse(str); 
}

7. 看看underscore1.11.0中是如何实现的:

function isArrayLike(obj) {
    var length = obj == null ? void 0: obj.length
    return typeof length == 'number' && length >= 0 && length <= Math.pow(2, 53) - 1;
}
function has(obj, key) {
    return obj != null && Object.prototype.hasOwnProperty.call(obj, key);
}
var isArray = Array.isArray|| function (obj) {
    return Object.prototype.toString.call(obj) === '[object Array]'
}
var isArguments = function (obj) {
    return Object.prototype.toString.call(obj) === '[object Arguments]'
}
// IE9以下没有Arguments类型
(function() {
    if (!isArguments(arguments)) {
        isArguments = function(obj) {
            return obj != null && Object.prototype.hasOwnProperty.call(obj, 'callee');
        }
    }
})();

function flatten(input, depth, strict, output) {
    output = output || [];
    if (!depth && depth !== 0) {
        depth = Infinity;
    } else if (depth <= 0) {
        return output.concat(input);
    }
    var idx = output.length;
    for (var i = 0, length = input.length; i < length; i++) {
        var value = input[i];
        if (isArrayLike(value) && (isArray(value) || isArguments$1(value))) {
            if (depth > 1) {
                flatten(value, depth - 1, strict, output);
                idx = output.length;
            } else {
                var j = 0, len = value.length;
                while (j < len) output[idx++] = value[j++];
            }
        } else if (!strict) {
            output[idx++] = value;
        }
    }
    return output;
}

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

参考资料: JavaScript专题之数组扁平化

MDN: Array.prototype.flat

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值