Tengo una matriz de JavaScript como:
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
¿Cómo haría para fusionar las matrices internas separadas en una como:
["$6", "$12", "$25", ...]
fuente
Tengo una matriz de JavaScript como:
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
¿Cómo haría para fusionar las matrices internas separadas en una como:
["$6", "$12", "$25", ...]
Puede usar concat
para fusionar matrices:
var arrays = [
["$6"],
["$12"],
["$25"],
["$25"],
["$18"],
["$22"],
["$10"]
];
var merged = [].concat.apply([], arrays);
console.log(merged);
Usar el apply
método de concat
solo tomará el segundo parámetro como una matriz, por lo que la última línea es idéntica a esta:
var merged2 = [].concat(["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]);
También existe el Array.prototype.flat()
método (introducido en ES2019) que podría usar para aplanar las matrices, aunque solo está disponible en Node.js a partir de la versión 11, y no está disponible en absoluto en Internet Explorer .
const arrays = [
["$6"],
["$12"],
["$25"],
["$25"],
["$18"],
["$22"],
["$10"]
];
const merge3 = arrays.flat(1); //The depth level specifying how deep a nested array structure should be flattened. Defaults to 1.
console.log(merge3);
concat
no modifica la matriz de origen, por lo que la merged
matriz permanecerá vacía después de la llamada a concat
. Mejor decir algo como:merged = merged.concat.apply(merged, arrays);
var merged = [].concat.apply([], arrays);
parece funcionar bien para obtenerlo en una línea. editar: como ya muestra la respuesta de Nikita.
Array.prototype.concat.apply([], arrays)
.
var merged = [].concat(...arrays)
Aquí hay una función corta que usa algunos de los métodos de matriz JavaScript más nuevos para aplanar una matriz n-dimensional.
function flatten(arr) {
return arr.reduce(function (flat, toFlatten) {
return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
}, []);
}
Uso:
flatten([[1, 2, 3], [4, 5]]); // [1, 2, 3, 4, 5]
flatten([[[1, [1.1]], 2, 3], [4, 5]]); // [1, 1.1, 2, 3, 4, 5]
flat
en la primera llamada a la función anónima pasada reduce
. Si no se especifica, entonces la primera llamada para reduce
vincular el primer valor fuera de la matriz flat
, lo que eventualmente resultaría 1
vinculado a flat
ambos ejemplos. 1.concat
No es una función.
const flatten = (arr) => arr.reduce((flat, next) => flat.concat(next), []);
const flatten = (arr) => arr.reduce((flat, next) => flat.concat(Array.isArray(next) ? flatten(next) : next), []);
Hay un método confusamente oculto, que construye una nueva matriz sin mutar la original:
var oldArray = [[1],[2,3],[4]];
var newArray = Array.prototype.concat.apply([], oldArray);
console.log(newArray); // [ 1, 2, 3, 4 ]
[].concat([[1],[2,3],[4]]...)
[[1],[2,3],[4]]
como resultado. La solución que da @Nikita es correcta tanto para CoffeeScript como para JS.
[].concat([1],[2,3],[4],...)
.
...
son de código real, no algunos puntos suspensivos.
Se puede hacer mejor con la función de reducción de JavaScript.
var arrays = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]];
arrays = arrays.reduce(function(a, b){
return a.concat(b);
}, []);
O con ES2015:
arrays = arrays.reduce((a, b) => a.concat(b), []);
[]
y no se necesitan más validaciones.
arrays.reduce((flatten, arr) => [...flatten, ...arr])
Hay un nuevo método nativo llamado plano para hacer esto exactamente.
(A fines de 2019, flat
ahora se publica en el estándar ECMA 2019, y core-js@3
(la biblioteca de babel) lo incluye en su biblioteca de polyfill )
const arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
const arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
// Flatten 2 levels deep
const arr3 = [2, 2, 5, [5, [5, [6]], 7]];
arr3.flat(2);
// [2, 2, 5, 5, 5, [6], 7];
// Flatten all levels
const arr4 = [2, 2, 5, [5, [5, [6]], 7]];
arr4.flat(Infinity);
// [2, 2, 5, 5, 5, 6, 7];
La mayoría de las respuestas aquí no funcionan en grandes matrices (por ejemplo, 200 000 elementos), e incluso si lo hacen, son lentas. La respuesta de polkovnikov.ph tiene el mejor rendimiento, pero no funciona para el aplanamiento profundo.
Aquí está la solución más rápida, que también funciona en matrices con múltiples niveles de anidamiento :
const flatten = function(arr, result = []) {
for (let i = 0, length = arr.length; i < length; i++) {
const value = arr[i];
if (Array.isArray(value)) {
flatten(value, result);
} else {
result.push(value);
}
}
return result;
};
flatten(Array(200000).fill([1]));
Maneja grandes matrices muy bien. En mi máquina, este código tarda unos 14 ms en ejecutarse.
flatten(Array(2).fill(Array(2).fill(Array(2).fill([1]))));
Funciona con matrices anidadas. Este código produce [1, 1, 1, 1, 1, 1, 1, 1]
.
flatten([1, [1], [[1]]]);
No tiene ningún problema al aplanar matrices como esta.
RangeError: Maximum call stack size exceeded
). Para una matriz de 20 000 elementos, tarda de 2 a 5 milisegundos.
Actualización: resultó que esta solución no funciona con matrices grandes. Si está buscando una solución mejor y más rápida, consulte esta respuesta .
function flatten(arr) {
return [].concat(...arr)
}
Simplemente se expande arr
y se lo pasa como argumentos a concat()
, lo que combina todas las matrices en una sola. Es equivalente a [].concat.apply([], arr)
.
También puede probar esto para el aplanamiento profundo:
function deepFlatten(arr) {
return flatten( // return shalowly flattened array
arr.map(x=> // with each x in array
Array.isArray(x) // is x an array?
? deepFlatten(x) // if yes, return deeply flattened x
: x // if no, return just x
)
)
}
Ver demo en JSBin .
Referencias para los elementos de ECMAScript 6 utilizados en esta respuesta:
Nota al margen: los métodos como find()
y las funciones de flecha no son compatibles con todos los navegadores, pero eso no significa que no pueda usar estas funciones en este momento. Simplemente use Babel : transforma el código ES6 en ES5.
apply
de esta manera, eliminé mis comentarios de los suyos. Todavía pienso utilizando apply
/ propagan de esta manera es mal consejo, pero ya nadie le importa ...
const flatten = arr => [].concat(...arr)
Puedes usar el subrayado :
var x = [[1], [2], [3, 4]];
_.flatten(x); // => [1, 2, 3, 4]
true
el segundo argumento .
Los procedimientos genéricos significan que no tenemos que reescribir la complejidad cada vez que necesitamos utilizar un comportamiento específico.
concatMap
(o flatMap
) es exactamente lo que necesitamos en esta situación.
// concat :: ([a],[a]) -> [a]
const concat = (xs,ys) =>
xs.concat (ys)
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = f => xs =>
xs.map(f).reduce(concat, [])
// id :: a -> a
const id = x =>
x
// flatten :: [[a]] -> [a]
const flatten =
concatMap (id)
// your sample data
const data =
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
console.log (flatten (data))
Y sí, lo has adivinado correctamente, solo se aplana un nivel, que es exactamente cómo debería funcionar
Imagina un conjunto de datos como este
// Player :: (String, Number) -> Player
const Player = (name,number) =>
[ name, number ]
// team :: ( . Player) -> Team
const Team = (...players) =>
players
// Game :: (Team, Team) -> Game
const Game = (teamA, teamB) =>
[ teamA, teamB ]
// sample data
const teamA =
Team (Player ('bob', 5), Player ('alice', 6))
const teamB =
Team (Player ('ricky', 4), Player ('julian', 2))
const game =
Game (teamA, teamB)
console.log (game)
// [ [ [ 'bob', 5 ], [ 'alice', 6 ] ],
// [ [ 'ricky', 4 ], [ 'julian', 2 ] ] ]
Ok, ahora digamos que queremos imprimir una lista que muestre a todos los jugadores que participarán en game
...
const gamePlayers = game =>
flatten (game)
gamePlayers (game)
// => [ [ 'bob', 5 ], [ 'alice', 6 ], [ 'ricky', 4 ], [ 'julian', 2 ] ]
Si nuestro flatten
procedimiento también aplanara las matrices anidadas, terminaríamos con este resultado basura ...
const gamePlayers = game =>
badGenericFlatten(game)
gamePlayers (game)
// => [ 'bob', 5, 'alice', 6, 'ricky', 4, 'julian', 2 ]
Eso no quiere decir que a veces no quieras aplanar matrices anidadas, solo que ese no debería ser el comportamiento predeterminado.
Podemos hacer un deepFlatten
procedimiento con facilidad ...
// concat :: ([a],[a]) -> [a]
const concat = (xs,ys) =>
xs.concat (ys)
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = f => xs =>
xs.map(f).reduce(concat, [])
// id :: a -> a
const id = x =>
x
// flatten :: [[a]] -> [a]
const flatten =
concatMap (id)
// deepFlatten :: [[a]] -> [a]
const deepFlatten =
concatMap (x =>
Array.isArray (x) ? deepFlatten (x) : x)
// your sample data
const data =
[0, [1, [2, [3, [4, 5], 6]]], [7, [8]], 9]
console.log (flatten (data))
// [ 0, 1, [ 2, [ 3, [ 4, 5 ], 6 ] ], 7, [ 8 ], 9 ]
console.log (deepFlatten (data))
// [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Allí. Ahora tiene una herramienta para cada trabajo: una para aplastar un nivel de anidamiento flatten
y otra para eliminar todo el anidamientodeepFlatten
.
Tal vez puedas llamarlo obliterate
o nuke
si no te gusta el nombre deepFlatten
.
¡No repitas dos veces!
Por supuesto, las implementaciones anteriores son inteligentes y concisas, pero el uso de un .map
seguido de un llamado a .reduce
significa que en realidad estamos haciendo más iteraciones de las necesarias
Usar un combinador de confianza al que llamo mapReduce
ayuda a mantener las iteraciones en un mínimo; toma una función de mapeo m :: a -> b
, una función reductora r :: (b,a) ->b
y devuelve una nueva función reductora: este combinador está en el corazón de los transductores ; si te interesa, he escrito otras respuestas sobre ellos
// mapReduce = (a -> b, (b,a) -> b, (b,a) -> b)
const mapReduce = (m,r) =>
(acc,x) => r (acc, m (x))
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = f => xs =>
xs.reduce (mapReduce (f, concat), [])
// concat :: ([a],[a]) -> [a]
const concat = (xs,ys) =>
xs.concat (ys)
// id :: a -> a
const id = x =>
x
// flatten :: [[a]] -> [a]
const flatten =
concatMap (id)
// deepFlatten :: [[a]] -> [a]
const deepFlatten =
concatMap (x =>
Array.isArray (x) ? deepFlatten (x) : x)
// your sample data
const data =
[ [ [ 1, 2 ],
[ 3, 4 ] ],
[ [ 5, 6 ],
[ 7, 8 ] ] ]
console.log (flatten (data))
// [ [ 1. 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ] ]
console.log (deepFlatten (data))
// [ 1, 2, 3, 4, 5, 6, 7, 8 ]
concat
sí no volar la pila, única ...
y apply
hace (junto con matrices muy grandes). No lo vi Me siento terrible en este momento.
concat
en Javascript tiene un significado diferente que en Haskell. Haskell's concat
( [[a]] -> [a]
) se llamaría flatten
en Javascript y se implementaría como foldr (++) []
(Javascript: foldr(concat) ([])
asumiendo funciones currificadas). Javascript concat
es un agregado extraño ( (++)
en Haskell), que puede manejar ambos [a] -> [a] -> [a]
y a -> [a] -> [a]
.
flatMap
, porque eso es exactamente lo que concatMap
es: la bind
instancia de la list
mónada. concatpMap
se implementa como foldr ((++) . f) []
. Traducido en Javascript: const flatMap = f => foldr(comp(concat) (f)) ([])
. Por supuesto, esto es similar a su implementación sin comp
.
Una solución para el caso más general, cuando puede tener algunos elementos que no son de matriz en su matriz.
function flattenArrayOfArrays(a, r){
if(!r){ r = []}
for(var i=0; i<a.length; i++){
if(a[i].constructor == Array){
r.concat(flattenArrayOfArrays(a[i], r));
}else{
r.push(a[i]);
}
}
return r;
}
Object.defineProperty(Array.prototype,'flatten',{value:function(r){for(var a=this,i=0,r=r||[];i<a.length;++i)if(a[i]!=null)a[i] instanceof Array?a[i].flatten(r):r.push(a[i]);return r}});
flattenArrayOfArrays (arr, 10)
o esto flattenArrayOfArrays(arr, [1,[3]]);
: esos segundos argumentos se agregan a la salida.
r
realmente concatene los resultados de la recursividad.
Para aplanar una matriz de matrices de un solo elemento, no necesita importar una biblioteca, un bucle simple es la solución más simple y más eficiente :
for (var i = 0; i < a.length; i++) {
a[i] = a[i][0];
}
Para los votantes negativos: lea la pregunta, no haga votos negativos porque no se adapta a su problema muy diferente. Esta solución es tanto la más rápida como la más simple para la pregunta formulada.
['foo', ['bar']]
a ['f', 'bar']
.
¿Qué pasa con el uso del reduce(callback[, initialValue])
método deJavaScript 1.8
list.reduce((p,n) => p.concat(n),[]);
Haría el trabajo
[[1], [2,3]].reduce( (a,b) => a.concat(b), [] )
Es más sexy.
[[1], [2,3]].reduce( (a,b) => a.concat(b))
Otra solución ECMAScript 6 en estilo funcional:
Declarar una función:
const flatten = arr => arr.reduce(
(a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []
);
y úsalo:
flatten( [1, [2,3], [4,[5,[6]]]] ) // -> [1,2,3,4,5,6]
const flatten = arr => arr.reduce(
(a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []
);
console.log( flatten([1, [2,3], [4,[5],[6,[7,8,9],10],11],[12],13]) )
Considere también una función nativa Array.prototype.flat () (propuesta para ES6) disponible en las últimas versiones de los navegadores modernos. Gracias a @ (Константин Ван) y @ (Mark Amery) lo mencionaron en los comentarios.
La flat
función tiene un parámetro, que especifica la profundidad esperada de la anidación de la matriz, que es igual 1
por defecto.
[1, 2, [3, 4]].flat(); // -> [1, 2, 3, 4]
[1, 2, [3, 4, [5, 6]]].flat(); // -> [1, 2, 3, 4, [5, 6]]
[1, 2, [3, 4, [5, 6]]].flat(2); // -> [1, 2, 3, 4, 5, 6]
[1, 2, [3, 4, [5, 6]]].flat(Infinity); // -> [1, 2, 3, 4, 5, 6]
let arr = [1, 2, [3, 4]];
console.log( arr.flat() );
arr = [1, 2, [3, 4, [5, 6]]];
console.log( arr.flat() );
console.log( arr.flat(1) );
console.log( arr.flat(2) );
console.log( arr.flat(Infinity) );
RangeError: Maximum call stack size exceeded
const common = arr.reduce((a, b) => [...a, ...b], [])
Tenga en cuenta: cuando se usa Function.prototype.apply
( [].concat.apply([], arrays)
) o el operador de propagación ( [].concat(...arrays)
) para aplanar una matriz, ambos pueden causar desbordamientos de la pila para matrices grandes, porque cada argumento de una función se almacena en la pila.
Aquí hay una implementación segura para la pila en un estilo funcional que sopesa los requisitos más importantes entre sí:
// small, reusable auxiliary functions:
const foldl = f => acc => xs => xs.reduce(uncurry(f), acc); // aka reduce
const uncurry = f => (a, b) => f(a) (b);
const concat = xs => y => xs.concat(y);
// the actual function to flatten an array - a self-explanatory one-line:
const flatten = xs => foldl(concat) ([]) (xs);
// arbitrary array sizes (until the heap blows up :D)
const xs = [[1,2,3],[4,5,6],[7,8,9]];
console.log(flatten(xs));
// Deriving a recursive solution for deeply nested arrays is trivially now
// yet more small, reusable auxiliary functions:
const map = f => xs => xs.map(apply(f));
const apply = f => a => f(a);
const isArray = Array.isArray;
// the derived recursive function:
const flattenr = xs => flatten(map(x => isArray(x) ? flattenr(x) : x) (xs));
const ys = [1,[2,[3,[4,[5],6,],7],8],9];
console.log(flattenr(ys));
Tan pronto como se acostumbre a las funciones de flecha pequeña en forma de curry, composición de funciones y funciones de orden superior, este código se lee como prosa. La programación consiste simplemente en juntar pequeños bloques de construcción que siempre funcionan como se espera, porque no contienen ningún efecto secundario.
const flatten = (arr) => arr.reduce((a, b) => a.concat(b), []);
ahorra basura visual y explica a sus compañeros de equipo por qué necesita 3 funciones adicionales y algunas llamadas a funciones también.
Ver aplanar lodash , subrayar aplanar (poco profundo true
)
function flatten(arr) {
return arr.reduce((acc, e) => acc.concat(e), []);
}
function flatten(arr) {
return [].concat.apply([], arr);
}
Probado con
test('already flatted', () => {
expect(flatten([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]);
});
test('flats first level', () => {
expect(flatten([1, [2, [3, [4]], 5]])).toEqual([1, 2, [3, [4]], 5]);
});
Ver aplanar lodash Profundo , subrayar aplanar
function flattenDeep(arr) {
return arr.reduce((acc, e) => Array.isArray(e) ? acc.concat(flattenDeep(e)) : acc.concat(e), []);
}
Probado con
test('already flatted', () => {
expect(flattenDeep([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]);
});
test('flats', () => {
expect(flattenDeep([1, [2, [3, [4]], 5]])).toEqual([1, 2, 3, 4, 5]);
});
Array.prototype.concat.apply([], arr)
porque crea una matriz adicional solo para acceder a la concat
función. Los tiempos de ejecución pueden o no optimizarlo cuando lo ejecutan, pero acceder a la función en el prototipo no parece más feo de lo que ya es en cualquier caso.
Puede usar Array.flat()
con Infinity
cualquier profundidad de matriz anidada.
var arr = [ [1,2,3,4], [1,2,[1,2,3]], [1,2,3,4,5,[1,2,3,4,[1,2,3,4]]], [[1,2,3,4], [1,2,[1,2,3]], [1,2,3,4,5,[1,2,3,4,[1,2,3,4]]]] ];
let flatten = arr.flat(Infinity)
console.log(flatten)
verifique aquí la compatibilidad del navegador
Un enfoque Haskellesque
function flatArray([x,...xs]){
return x ? [...Array.isArray(x) ? flatArray(x) : [x], ...flatArray(xs)] : [];
}
var na = [[1,2],[3,[4,5]],[6,7,[[[8],9]]],10];
fa = flatArray(na);
console.log(fa);
Manera ES6:
const flatten = arr => arr.reduce((acc, next) => acc.concat(Array.isArray(next) ? flatten(next) : next), [])
const a = [1, [2, [3, [4, [5]]]]]
console.log(flatten(a))
Forma ES5 para la flatten
función con el respaldo ES3 para matrices anidadas N veces:
var flatten = (function() {
if (!!Array.prototype.reduce && !!Array.isArray) {
return function(array) {
return array.reduce(function(prev, next) {
return prev.concat(Array.isArray(next) ? flatten(next) : next);
}, []);
};
} else {
return function(array) {
var arr = [];
var i = 0;
var len = array.length;
var target;
for (; i < len; i++) {
target = array[i];
arr = arr.concat(
(Object.prototype.toString.call(target) === '[object Array]') ? flatten(target) : target
);
}
return arr;
};
}
}());
var a = [1, [2, [3, [4, [5]]]]];
console.log(flatten(a));
Si solo tiene matrices con 1 elemento de cadena:
[["$6"], ["$12"], ["$25"], ["$25"]].join(',').split(',');
Hará el trabajo. Bt que coincide específicamente con su ejemplo de código.
['$4', ["$6"], ["$12"], ["$25"], ["$25", "$33", ['$45']]].join(',').split(',')
[1,4, [45, 't', ['e3', 6]]].toString().split(',')
---- o ----- [1,4, [45, 't', ['e3', 6], false]].toString().split(',')
var arrays = [["a"], ["b", "c"]];
Array.prototype.concat.apply([], arrays);
// gives ["a", "b", "c"]
(Solo estoy escribiendo esto como una respuesta separada, basada en el comentario de @danhbear).
Recomiendo una función de generador de espacio eficiente :
function* flatten(arr) {
if (!Array.isArray(arr)) yield arr;
else for (let el of arr) yield* flatten(el);
}
// Example:
console.log(...flatten([1,[2,[3,[4]]]])); // 1 2 3 4
Si lo desea, cree una matriz de valores aplanados de la siguiente manera:
let flattened = [...flatten([1,[2,[3,[4]]]])]; // [1, 2, 3, 4]
...
para iterar a través del generador.
Prefiero transformar toda la matriz, tal cual, en una cadena, pero a diferencia de otras respuestas, lo haría usando JSON.stringify
y no el toString()
método, que produce un resultado no deseado.
Con esa JSON.stringify
salida, todo lo que queda es eliminar todos los corchetes, ajustar el resultado con los corchetes de inicio y finalización una vez más, y servir el resultado con el JSON.parse
que la cadena vuelve a la "vida".
var arr = ["abc",[[[6]]],["3,4"],"2"];
var s = "[" + JSON.stringify(arr).replace(/\[|]/g,'') +"]";
var flattened = JSON.parse(s);
console.log(flattened)
["345", "2", "3,4", "2"]
lugar de separar cada uno de esos valores para separar los índices
"3,4"
.
También puedes probar el nuevo Array.Flat()
método. Funciona de la siguiente manera:
let arr = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]].flat()
console.log(arr);
El flat()
método crea una nueva matriz con todos los elementos de la sub-matriz concatenados recursivamente hasta la capa de profundidad 1 (es decir, matrices dentro de las matrices)
Si también desea aplanar matrices tridimensionales o incluso de dimensiones superiores, simplemente llame al método plano varias veces. Por ejemplo (3 dimensiones):
let arr = [1,2,[3,4,[5,6]]].flat().flat().flat();
console.log(arr);
Array.Flat()
El método es relativamente nuevo. Los navegadores más antiguos como ie podrían no haber implementado el método. Si desea que el código funcione en todos los navegadores, es posible que deba transpilar su JS a una versión anterior. Verifique los documentos web de MD para ver la compatibilidad actual del navegador.
Infinity
argumento. Así:arr.flat(Infinity)
Usando el operador de propagación:
const input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]];
const output = [].concat(...input);
console.log(output); // --> ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]
Eso no es difícil, solo itera sobre las matrices y únelas:
var result = [], input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"]];
for (var i = 0; i < input.length; ++i) {
result = result.concat(input[i]);
}
¡Parece que esto parece un trabajo para RECURSION!
Código:
var flatten = function(toFlatten) {
var isArray = Object.prototype.toString.call(toFlatten) === '[object Array]';
if (isArray && toFlatten.length > 0) {
var head = toFlatten[0];
var tail = toFlatten.slice(1);
return flatten(head).concat(flatten(tail));
} else {
return [].concat(toFlatten);
}
};
Uso:
flatten([1,[2,3],4,[[5,6],7]]);
// Result: [1, 2, 3, 4, 5, 6, 7]
flatten(new Array(15000).fill([1]))
lanza Uncaught RangeError: Maximum call stack size exceeded
y congela mis devTools por 10 segundos
Lo hice usando recursividad y cierres
function flatten(arr) {
var temp = [];
function recursiveFlatten(arr) {
for(var i = 0; i < arr.length; i++) {
if(Array.isArray(arr[i])) {
recursiveFlatten(arr[i]);
} else {
temp.push(arr[i]);
}
}
}
recursiveFlatten(arr);
return temp;
}
Estaba haciendo el tonto con los generadores ES6 el otro día y escribí esta esencia . Que contiene...
function flatten(arrayOfArrays=[]){
function* flatgen() {
for( let item of arrayOfArrays ) {
if ( Array.isArray( item )) {
yield* flatten(item)
} else {
yield item
}
}
}
return [...flatgen()];
}
var flatArray = flatten([[1, [4]],[2],[3]]);
console.log(flatArray);
Básicamente, estoy creando un generador que recorre la matriz de entrada original, si encuentra una matriz, utiliza el operador de rendimiento * en combinación con la recursión para aplanar continuamente las matrices internas. Si el artículo no es una matriz, solo produce el artículo individual. Luego, utilizando el operador ES6 Spread (también conocido como operador splat), aplané el generador en una nueva instancia de matriz.
No he probado el rendimiento de esto, pero creo que es un buen ejemplo simple del uso de generadores y el operador de rendimiento *.
Pero nuevamente, solo estaba haciendo el ridículo, así que estoy seguro de que hay formas más efectivas de hacer esto.
la mejor solución sin lodash
let flatten = arr => [].concat.apply([], arr.map(item => Array.isArray(item) ? flatten(item) : item))
reduce
+concat
son O ((N ^ 2) / 2) donde como respuesta aceptada (solo una llamada aconcat
) sería como máximo O (N * 2) en un navegador defectuoso y O (N) en un bueno Además, la solución de Denys está optimizada para la pregunta real y hasta 2 veces más rápido que la únicaconcat
. Para lareduce
gente, es divertido sentirse bien escribiendo un código pequeño, pero por ejemplo, si la matriz tuviera 1000 subarreglos de un elemento, todas las soluciones reduce + concat estarían haciendo 500500 operaciones, mientras que el concat único o el bucle simple harían 1000 operaciones.[].concat(...array)
array.flat(Infinity)
dóndeInfinity
está la profundidad máxima para aplanar?