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", ...]
javascript
arrays
flatten
Andy
fuente
fuente
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?Respuestas:
Puede usar
concat
para fusionar matrices:Usar el
apply
método deconcat
solo tomará el segundo parámetro como una matriz, por lo que la última línea es idéntica a esta: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 .fuente
concat
no modifica la matriz de origen, por lo que lamerged
matriz permanecerá vacía después de la llamada aconcat
. 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.
Uso:
fuente
flat
en la primera llamada a la función anónima pasadareduce
. Si no se especifica, entonces la primera llamada parareduce
vincular el primer valor fuera de la matrizflat
, lo que eventualmente resultaría1
vinculado aflat
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:
fuente
[].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.
O con ES2015:
js-violín
Documentos de Mozilla
fuente
[]
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, ycore-js@3
(la biblioteca de babel) lo incluye en su biblioteca de polyfill )fuente
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 :
Ejemplos
Enormes matrices
Maneja grandes matrices muy bien. En mi máquina, este código tarda unos 14 ms en ejecutarse.
Matrices anidadas
Funciona con matrices anidadas. Este código produce
[1, 1, 1, 1, 1, 1, 1, 1]
.Matrices con diferentes niveles de anidamiento
No tiene ningún problema al aplanar matrices como esta.
fuente
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 .
Simplemente se expande
arr
y se lo pasa como argumentos aconcat()
, lo que combina todas las matrices en una sola. Es equivalente a[].concat.apply([], arr)
.También puede probar esto para el aplanamiento profundo:
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.fuente
apply
de esta manera, eliminé mis comentarios de los suyos. Todavía pienso utilizandoapply
/ propagan de esta manera es mal consejo, pero ya nadie le importa ...const flatten = arr => [].concat(...arr)
Puedes usar el subrayado :
fuente
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
(oflatMap
) es exactamente lo que necesitamos en esta situación.previsión
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
Ok, ahora digamos que queremos imprimir una lista que muestre a todos los jugadores que participarán en
game
...Si nuestro
flatten
procedimiento también aplanara las matrices anidadas, terminaríamos con este resultado basura ...rodando profundo, bebé
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 ...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
onuke
si no te gusta el nombredeepFlatten
.¡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 necesariasUsar un combinador de confianza al que llamo
mapReduce
ayuda a mantener las iteraciones en un mínimo; toma una función de mapeom :: a -> b
, una función reductorar :: (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 ellosfuente
concat
sí no volar la pila, única...
yapply
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'sconcat
([[a]] -> [a]
) se llamaríaflatten
en Javascript y se implementaría comofoldr (++) []
(Javascript:foldr(concat) ([])
asumiendo funciones currificadas). Javascriptconcat
es un agregado extraño ((++)
en Haskell), que puede manejar ambos[a] -> [a] -> [a]
ya -> [a] -> [a]
.flatMap
, porque eso es exactamente lo queconcatMap
es: labind
instancia de lalist
mónada.concatpMap
se implementa comofoldr ((++) . f) []
. Traducido en Javascript:const flatMap = f => foldr(comp(concat) (f)) ([])
. Por supuesto, esto es similar a su implementación sincomp
.Una solución para el caso más general, cuando puede tener algunos elementos que no son de matriz en su matriz.
fuente
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 estoflattenArrayOfArrays(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 :
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.
fuente
['foo', ['bar']]
a['f', 'bar']
.¿Qué pasa con el uso del
reduce(callback[, initialValue])
método deJavaScript 1.8
Haría el trabajo
fuente
[[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:
y úsalo:
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 igual1
por defecto.fuente
RangeError: Maximum call stack size exceeded
fuente
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í:
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.
fuente
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.ES6 One Line Flatten
Ver aplanar lodash , subrayar aplanar (poco profundo
true
)o
Probado con
ES6 One Line Deep Flatten
Ver aplanar lodash Profundo , subrayar aplanar
Probado con
fuente
Array.prototype.concat.apply([], arr)
porque crea una matriz adicional solo para acceder a laconcat
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()
conInfinity
cualquier profundidad de matriz anidada.verifique aquí la compatibilidad del navegador
fuente
Un enfoque Haskellesque
fuente
Manera ES6:
Forma ES5 para la
flatten
función con el respaldo ES3 para matrices anidadas N veces:fuente
Si solo tiene matrices con 1 elemento de cadena:
Hará el trabajo. Bt que coincide específicamente con su ejemplo de código.
fuente
['$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(',')
(Solo estoy escribiendo esto como una respuesta separada, basada en el comentario de @danhbear).
fuente
Recomiendo una función de generador de espacio eficiente :
Si lo desea, cree una matriz de valores aplanados de la siguiente manera:
fuente
...
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 eltoString()
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 elJSON.parse
que la cadena vuelve a la "vida".fuente
["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: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):
¡Ten cuidado!
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.fuente
Infinity
argumento. Así:arr.flat(Infinity)
Usando el operador de propagación:
fuente
Eso no es difícil, solo itera sobre las matrices y únelas:
fuente
¡Parece que esto parece un trabajo para RECURSION!
Código:
Uso:
fuente
flatten(new Array(15000).fill([1]))
lanzaUncaught RangeError: Maximum call stack size exceeded
y congela mis devTools por 10 segundosLo hice usando recursividad y cierres
fuente
Estaba haciendo el tonto con los generadores ES6 el otro día y escribí esta esencia . Que contiene...
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.
fuente
la mejor solución sin lodash
fuente