如何在javascript中展平嵌套数组?

zan*_*ngw 31 javascript arrays

我们知道,[[0, 1], [2, 3], [4, 5]]使用该方法展平数组reduce()

var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
  return a.concat(b);
});
Run Code Online (Sandbox Code Playgroud)

因此,如何扁平化这个数组[[[0], [1]], [[2], [3]], [[4], [5]]][0, 1, 2, 3, 4, 5]

Leo*_*Leo 43

递归的完美用例,可以处理更深层次的结构:

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

flatten([[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]]) // [0, 1, 2, 3, 4, 5]
Run Code Online (Sandbox Code Playgroud)

或者,作为Array方法:

Array.prototype.flatten = function() {
    var ret = [];
    for(var i = 0; i < this.length; i++) {
        if(Array.isArray(this[i])) {
            ret = ret.concat(this[i].flatten());
        } else {
            ret.push(this[i]);
        }
    }
    return ret;
};

[[[[[0]], [1]], [[[2], [3]]], [[4], [5]]]].flatten() // [0, 1, 2, 3, 4, 5]
Run Code Online (Sandbox Code Playgroud)

编辑:嗯,认为它有点功能方式(除了命名的递归应该使用Y-combinator纯功能:D).

function flatten(ary) {
  return ary.reduce(function(a, b) {
    if (Array.isArray(b)) {
      return a.concat(flatten(b))
    }
    return a.concat(b)
  }, [])
}
Run Code Online (Sandbox Code Playgroud)

让我们采用一些ES6语法,使其更短,在一行中.

const flatten = (ary) => ary.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [])
Run Code Online (Sandbox Code Playgroud)

但请记住,这个不能用作数组方法,因为箭头函数没有自己的this.


Ink*_*ing 41

ES6风格的递归:

function flatten(arr) {
  const flat = [].concat(...arr);
  return flat.some(Array.isArray) ? flatten(flat) : flat;
}
Run Code Online (Sandbox Code Playgroud)

效率不高,所以除了相对琐碎的情况外,不要使用任何东西,但它至少看起来不错.


2018年6月更新:

现在有一个Array.prototype.flat方法的ES提议.它目前处于第3阶段,这意味着它可能很快就会被浏览器实现(ish),并使其成为当前形式的规范.可能有一些聚四氟乙烯漂浮在周围.

例:

const nested = [[[0], [1]], [[2], [3]], [[4], [5]]];
const flattened = nested.flat(2);  // Need to specify depth if > 1
Run Code Online (Sandbox Code Playgroud)


axe*_*uch 32

这是递归的替代方法(请参阅此处的jsfiddle),并且应该接受任何级别的深度,以避免堆栈溢出.

var array = [[0, 1], [2, 3], [4, 5, [6, 7, [8, [9, 10]]]]];
console.log(flatten(array), array); // does not mutate array
console.log(flatten(array, true), array); // array is now empty

// This is done in a linear time O(n) without recursion
// memory complexity is O(1) or O(n) if mutable param is set to false
function flatten(array, mutable) {
    var toString = Object.prototype.toString;
    var arrayTypeStr = '[object Array]';
    
    var result = [];
    var nodes = (mutable && array) || array.slice();
    var node;

    if (!array.length) {
        return result;
    }

    node = nodes.pop();
    
    do {
        if (toString.call(node) === arrayTypeStr) {
            nodes.push.apply(nodes, node);
        } else {
            result.push(node);
        }
    } while (nodes.length && (node = nodes.pop()) !== undefined);

    result.reverse(); // we reverse result to restore the original order
    return result;
}
Run Code Online (Sandbox Code Playgroud)

  • 偷偷摸摸地使用在那里分开arr,喜欢它. (6认同)
  • 你为什么使用`Object.prototype.toString.call(node)=='[object Array]'`而不是`Array.isArray(node)`? (2认同)
  • 它只适用于ie8及以下 (2认同)

mat*_*nso 13

ES6单线:

function flatten(a) {
    return Array.isArray(a) ? [].concat(...a.map(flatten)) : a;
}
Run Code Online (Sandbox Code Playgroud)

此外,非深层数组的非递归版本(效率不高但相当优雅)

function flatten(a) {
    var queue = a.slice();
    var result = [];
    while(queue.length) {
        let curr = queue.pop();
        if(Array.isArray(curr)) {
            queue.push(...curr);
        }
        else result.push(curr);
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)


Tim*_* Gu 10

基于@Leo的解决方案,但通过重用相同的阵列并防止更快 .concat

function flatten(ary, ret) {
    ret = ret === undefined ? [] : ret;
    for (var i = 0; i < ary.length; i++) {
        if (Array.isArray(ary[i])) {
            flatten(ary[i], ret);
        } else {
            ret.push(ary[i]);
        }
    }
    return ret;
}
Run Code Online (Sandbox Code Playgroud)

例:

function flatten(ary, ret) {
  ret = ret === undefined ? [] : ret;
  for (var i = 0; i < ary.length; i++) {
    if (Array.isArray(ary[i])) {
      flatten(ary[i], ret);
    } else {
      ret.push(ary[i]);
    }
  }
  return ret;
}
console.log(flatten([[[0], [1]], [[2], [3]], [[4], [5]]]));
Run Code Online (Sandbox Code Playgroud)

或者Array.prototype.reduce,因为你提到它:

function flatten(ary, ret) {
    return ary.reduce(function(ret, entry) {
        if (Array.isArray(entry)) {
            flatten(entry, ret);
        } else {
            ret.push(entry);
        }
        return ret;
    }, ret || []);
}
Run Code Online (Sandbox Code Playgroud)

例:

function flatten(ary, ret) {
  return ary.reduce(function(ret, entry) {
    if (Array.isArray(entry)) {
      flatten(entry, ret);
    } else {
      ret.push(entry);
    }
    return ret;
  }, ret || []);
}
console.log(flatten([[[0], [1]], [[2], [3]], [[4], [5]]]));
Run Code Online (Sandbox Code Playgroud)


art*_*pro 7

仅展平2个级别:

var arr = [1, [2, 3], [4, 5, 6]];
[].concat.apply([], arr) // -> [1, 2, 3, 4, 5, 6]
Run Code Online (Sandbox Code Playgroud)


小智 5

这已经得到了回答,但我只是在学习 JS 并想知道:

    var array = [[[0], [1]], [[2], [3]], [[4], [5]]];
    var flattend = array.join(",").split(",");
    console.log(flattend);
Run Code Online (Sandbox Code Playgroud)

唯一的副作用是连接将所有项目转换为字符串,但这可以很容易地修复

  • 对于数字和字符串,这个解决方案非常聪明,但是当涉及对象和函数时,问题变得更加复杂。 (6认同)

das*_*les 5

我喜欢我的解决方案:)

var flattenClosure = function(a) {
    var store = [];

    return function() {
        var internMapper = function(b) {
            if (Array.isArray(b)) {
                return b.map(internMapper);
            }
            store.push(b);
            return b;
        }
        a.map(internMapper);
        return store;
    }
};

console.log(flattenClosure([[[[[[[[1]]]], [2], [4], [6, 8, 9], 2]]], 10, 11, [15, 17, 20], [], 33])());
Run Code Online (Sandbox Code Playgroud)