without unir two sort objects functions array javascript arrays flatten

unir - ¿Combinar/aplanar una matriz de matrices en JavaScript?



javascript sort array by two properties (30)

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", ...]


ES6 One Line Flatten

Vea el aplanamiento de lodash , el subrayado aplanar (poco profundo)

function flatten(arr) { return arr.reduce((acc, e) => acc.concat(e), []); }

or

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]); });

ES6 One Line Deep Flatten

Ver lodash aplanar , 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]); });


¡Parece que esto parece un trabajo para RECURSION!

  • Maneja múltiples niveles de anidación.
  • Maneja matrices vacías y parámetros no matriciales
  • No tiene mutacion
  • No confía en las características modernas del navegador

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]


¿Qué hay de usar el método de reduce(callback[, initialValue]) de JavaScript 1.8

list.reduce((p,n) => p.concat(n),[]);

Haría el trabajo.


Aquí hay una función corta que utiliza algunos de los nuevos métodos de matriz de JavaScript 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]


Aquí hay una solución funcional simple y de alto rendimiento:

var result = [].concat.apply([], [[1],[2,3],[4]]); console.log(result); // [ 1, 2, 3, 4 ]

No hay lío imperativo.


ES6 forma:

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))

ES5 forma para flatten función con ES3 retroceso para matrices anidadas N-times:

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));



La mayoría de las respuestas aquí no funcionan en arreglos enormes (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 un aplanamiento profundo.

Aquí está la solución más rápida, que funciona también en arreglos 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; };

Ejemplos

Enormes matrices

flatten(Array(200000).fill([1]));

Se maneja enormes matrices muy bien. En mi máquina este código tarda aproximadamente 14 ms en ejecutarse.

Matrices anidadas

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] .

Arreglos con diferentes niveles de anidación.

flatten([1, [1], [[1]]]);

No tiene ningún problema con las matrices de aplanamiento como esta.


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))

previsión

Y sí, lo adivinaste correctamente, solo 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 el game ...

const gamePlayers = game => flatten (game) gamePlayers (game) // => [ [ ''bob'', 5 ], [ ''alice'', 6 ], [ ''ricky'', 4 ], [ ''julian'', 2 ] ]

Si nuestro procedimiento de aplanamiento aplanara las matrices anidadas también, terminaríamos con este resultado de basura ...

const gamePlayers = game => badGenericFlatten(game) gamePlayers (game) // => [ ''bob'', 5, ''alice'', 6, ''ricky'', 4, ''julian'', 2 ]

rollin ''deep, baby

Esto no quiere decir que, a veces, tampoco desee aplanar matrices anidadas, solo que no debería ser el comportamiento predeterminado.

Podemos hacer un procedimiento de deepFlatten 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 ]

Ahí. Ahora tiene una herramienta para cada trabajo: una para aplastar un nivel de anidamiento, flatten y otra para deepFlatten todo anidamiento deepFlatten .

Tal vez pueda llamarlo obliterate o nuke si no le gusta el nombre deepFlatten .

¡No itere dos veces!

Por supuesto, las implementaciones anteriores son inteligentes y concisas, pero usar un .map seguido de una llamada a .reduce significa que en realidad estamos haciendo más iteraciones de las necesarias.

Al usar un combinador confiable, lo que llamo mapReduce ayuda a mantener las iteraciones a 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 ]


Otra solución ECMAScript 6 en estilo funcional:

Función de declaració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]


Para aplanar una matriz de matrices de un solo elemento, no necesita importar una biblioteca, un simple bucle es la solución más simple y eficiente :

for (var i = 0; i < a.length; i++) { a[i] = a[i][0]; }

A los votantes: lea la pregunta, no vote porque no se adapta a su problema muy diferente. Esta solución es tanto la más rápida como la más sencilla para la pregunta formulada.


Preferiría transformar toda la matriz, como está, en una cadena, pero a diferencia de otras respuestas, haría eso utilizando JSON.stringify y no usaría el método toString() , que produce un resultado no deseado.

Con esa salida de JSON.stringify , todo lo que queda es eliminar todos los corchetes, envolver el resultado con los corchetes iniciales y finales una vez más, y JSON.parse el resultado con JSON.parse que devuelve la cadena a "vida".

  • Puede manejar infinitos arreglos anidados sin ningún costo de velocidad.
  • Puede manejar correctamente los elementos de la matriz que son cadenas que contienen comas.

var arr = ["abc",[[[6]]],["3,4"],"2"]; var s = "[" + JSON.stringify(arr).replace(//[|]/g,'''') +"]"; var flattened = JSON.parse(s); console.log(flattened)

  • Solo para matrices multidimensionales de cadenas / números (no objetos)

Puedes usar concat para unir matrices:

var arrays = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]; var merged = [].concat.apply([], arrays);

El uso del método de apply 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"]);


Puedes usar el Underscore :

var x = [[1], [2], [3, 4]]; _.flatten(x); // => [1, 2, 3, 4]


Se puede hacer mejor con javascript reducir la función.

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 bien, con ES2015:

arrays = arrays.reduce((a, b) => a.concat(b), []);

js-fiddle

Docs de mozilla


Si solo tienes 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.


Una solución para el caso más general, cuando puede tener algunos elementos no 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; }


Actualización: resultó que esta solución no funciona con matrices grandes. Si estás buscando una solución mejor y más rápida, revisa esta respuesta .

function flatten(arr) { return [].concat(...arr) }

Simplemente expande arr y lo pasa como argumentos a concat() , que combina todas las matrices en una sola. Es equivalente a [].concat.apply([], arr) .

También puedes probar esto para un 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: 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. Solo usa Babel - transforma el código ES6 en ES5.


Tenga en cuenta que cuando se [].concat.apply([], arrays) Function.prototype.apply ( [].concat.apply([], arrays) ) o el operador de propagación ( [].concat(...arrays) ) para aplanar una matriz, ambos pueden provoca desbordamientos de pila para arreglos 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í:

  • reutilización
  • legibilidad
  • concisión
  • actuación

// 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 te acostumbras a las funciones de flecha pequeña en forma de curry, composición de función y funciones de orden superior, este código se lee como prosa. La programación consiste simplemente en armar pequeños bloques de construcción que siempre funcionan como se espera, ya que no contienen ningún efecto secundario.


Eso no es difícil, solo iterar sobre los arreglos y fusionarlos:

var result = [], input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"]]; for (var i = 0; i < input.length; ++i) { result = result.concat(input[i]); }


La mejor solución sin lodash.

let flatten = arr => [].concat.apply([], arr.map(item => Array.isArray(item) ? flatten(item) : item))


Lo he hecho utilizando recursión 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; }


Un enfoque haskellesco.

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);


El otro día estuve jugando con ES6 Generators 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 yield* en combinación con la recursión para aplanar continuamente las matrices internas. Si el elemento no es una matriz, solo yields el elemento individual. Luego, utilizando el operador Spread de ES6 (también conocido como splat operator) aplané el generador en una nueva instancia de matriz.

No he probado el rendimiento de esto, pero creo que es un buen ejemplo simple de usar generadores y el operador de rendimiento *.

Pero una vez más, solo estaba haciendo el tonto, así que estoy seguro de que hay formas más eficaces de hacer esto.


La lógica aquí es convertir la matriz de entrada en cadena y eliminar todos los corchetes ([]) y analizar la salida a la matriz. Estoy usando la función de plantilla ES6 para esto.

var x=[1, 2, [3, 4, [5, 6,[7], 9],12, [12, 14]]]; var y=JSON.parse(`[${JSON.stringify(x).replace(//[|]/g,'''')}]`); console.log(y)


Propongo dos soluciones cortas sin recursión. No son óptimos desde el punto de vista de la complejidad computacional, pero funcionan bien en casos promedio:

let a = [1, [2, 3], [[4], 5, 6], 7, 8, [9, [[10]]]]; // Solution #1 while (a.find(x => Array.isArray(x))) a = a.reduce((x, y) => x.concat(y), []); // Solution #2 let i = a.findIndex(x => Array.isArray(x)); while (i > -1) { a.splice(i, 1, ...a[i]); i = a.findIndex(x => Array.isArray(x)); }


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 como sigue:

let flattened = [...flatten([1,[2,[3,[4]]]])]; // [1, 2, 3, 4]


const common = arr.reduce((a, b) => [...a, ...b], [])


const flatten = array => array.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);

Por solicitud, Romper la línea es básicamente tener esto.

function flatten(array) { // reduce traverses the array and we return the result return array.reduce(function(acc, b) { // if is an array we use recursion to perform the same operations over the array we found // else we just concat the element to the accumulator return acc.concat( Array.isArray(b) ? flatten(b) : b); }, []); // we initialize the accumulator on an empty array to collect all the elements }


var arrays = [["a"], ["b", "c"]]; Array.prototype.concat.apply([], arrays); // gives ["a", "b", "c"]

(Solo escribo esto como una respuesta separada, basada en el comentario de @danhbear).