Eu tenho uma matriz JavaScript como:
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
Como eu iria mesclar as matrizes internas separadas em uma como:
["$6", "$12", "$25", ...]
javascript
arrays
flatten
Andy
fonte
fonte
reduce
+concat
são O ((N ^ 2) / 2), onde como resposta aceita (apenas uma chamada paraconcat
) seria no máximo O (N * 2) em um navegador ruim e O (N) em um um bom. A solução Denys também é otimizada para a pergunta real e até 2x mais rápida que a únicaconcat
. Para asreduce
pessoas, é divertido sentir-se bem ao escrever códigos minúsculos, mas, por exemplo, se o array tivesse 1000 subarrays de um elemento, todas as soluções reduz + concat estariam executando operações 500500, onde o concat único ou o loop simples faria 1000 operações.[].concat(...array)
array.flat(Infinity)
ondeInfinity
está a profundidade máxima a nivelar.Respostas:
Você pode usar
concat
para mesclar matrizes:Usando o
apply
método deconcat
, apenas o segundo parâmetro será usado como uma matriz; portanto, a última linha é idêntica a esta:Há também o
Array.prototype.flat()
método (introduzido no ES2019) que você pode usar para nivelar as matrizes, embora ele esteja disponível apenas no Node.js, começando na versão 11, e nem no Internet Explorer .fonte
concat
não modifica a matriz de origem; portanto, amerged
matriz permanecerá vazia após a chamada paraconcat
. Melhor dizer algo como:merged = merged.concat.apply(merged, arrays);
var merged = [].concat.apply([], arrays);
parece funcionar bem para colocá-lo em uma linha. editar: como a resposta de Nikita já mostra.Array.prototype.concat.apply([], arrays)
.var merged = [].concat(...arrays)
Aqui está uma função curta que usa alguns dos métodos mais recentes de matriz JavaScript para nivelar uma matriz n-dimensional.
Uso:
fonte
flat
primeira chamada para a função anônima passada parareduce
. Se não for especificado, a primeira chamada areduce
vincular o primeiro valor da matriz aflat
, o que acabaria resultando em1
vinculaçãoflat
nos dois exemplos.1.concat
não é uma função.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), []);
Existe um método confuso, oculto, que constrói uma nova matriz sem alterar a original:
fonte
[].concat([[1],[2,3],[4]]...)
[[1],[2,3],[4]]
como resultado. A solução que o @Nikita fornece está correta para o CoffeeScript e para o JS.[].concat([1],[2,3],[4],...)
....
são código real, não algumas reticências.Pode ser feito melhor com a função de redução de javascript.
Ou, com o ES2015:
js-fiddle
Documentos do Mozilla
fonte
[]
e nenhuma validação adicional é necessária.arrays.reduce((flatten, arr) => [...flatten, ...arr])
Há um novo método nativo chamado flat para fazer exatamente isso.
(A partir do final de 2019,
flat
agora é publicado no padrão ECMA 2019 ecore-js@3
(a biblioteca de babel) inclui-o em sua biblioteca de polyfill )fonte
A maioria das respostas aqui não funciona em matrizes enormes (por exemplo, 200.000 elementos) e, mesmo se o fizerem, são lentas. A resposta de polkovnikov.ph tem o melhor desempenho, mas não funciona para achatamento profundo.
Aqui está a solução mais rápida, que também funciona em matrizes com vários níveis de aninhamento :
Exemplos
Matrizes enormes
Ele lida com matrizes enormes muito bem. Na minha máquina, esse código leva cerca de 14 ms para ser executado.
Matrizes aninhadas
Funciona com matrizes aninhadas. Este código produz
[1, 1, 1, 1, 1, 1, 1, 1]
.Matrizes com diferentes níveis de aninhamento
Ele não tem nenhum problema ao nivelar matrizes como esta.
fonte
RangeError: Maximum call stack size exceeded
). Para uma matriz de 20.000 elementos, leva de 2 a 5 milissegundos.Atualização: verificou-se que esta solução não funciona com matrizes grandes. Se você está procurando uma solução melhor e mais rápida, confira esta resposta .
É simplesmente expande
arr
e passa como argumentos paraconcat()
, que mescla todas as matrizes em uma. É equivalente a[].concat.apply([], arr)
.Você também pode tentar isso para achatamento profundo:
Veja a demonstração no JSBin .
Referências para os elementos do ECMAScript 6 usados nesta resposta:
Nota lateral: métodos como
find()
e funções de seta não são compatíveis com todos os navegadores, mas isso não significa que você não possa usar esses recursos no momento. Basta usar o Babel - ele transforma o código ES6 em ES5.fonte
apply
dessa maneira, removi meus comentários dos seus. Eu ainda acho que usandoapply
/ espalhar desta maneira é ruim aconselhar, mas desde que ninguém se importa ...const flatten = arr => [].concat(...arr)
Você pode usar o sublinhado :
fonte
true
o segundo argumento .Procedimentos genéricos significam que não precisamos reescrever a complexidade toda vez que precisamos utilizar um comportamento específico.
concatMap
(ouflatMap
) é exatamente o que precisamos nessa situação.previsão
E sim, você adivinhou corretamente, apenas nivela um nível, que é exatamente como deve funcionar
Imagine alguns conjuntos de dados como este
Ok, agora digamos que queremos imprimir uma lista que mostre todos os jogadores que participarão
game
…Se nosso
flatten
procedimento também nivelar matrizes aninhadas, acabaremos com esse resultado de lixo ...rolando fundo, baby
Isso não quer dizer que às vezes você também não queira achatar matrizes aninhadas - apenas esse não deve ser o comportamento padrão.
Podemos fazer um
deepFlatten
procedimento com facilidade…Lá. Agora você tem uma ferramenta para cada trabalho - uma para esmagar um nível de aninhamento
flatten
e outra para obliterar todos os aninhamentosdeepFlatten
.Talvez você possa ligar
obliterate
ounuke
se não gostar do nomedeepFlatten
.Não itere duas vezes!
É claro que as implementações acima são inteligentes e concisas, mas usar um
.map
seguido de uma chamada para.reduce
significa que estamos realmente fazendo mais iterações do que o necessárioUsar um combinador confiável que estou chamando
mapReduce
ajuda a manter as iterações em um mínimo; requer uma função de mapeamentom :: a -> b
, uma função redutorar :: (b,a) ->b
e retorna uma nova função redutora - esse combinador está no coração dos transdutores ; se você estiver interessado, eu escrevi outras respostas sobre elesfonte
concat
si não explodir a pilha, única...
eapply
faz (juntamente com matrizes muito grandes). Eu não vi. Eu me sinto terrível agora.concat
em Javascript tem um significado diferente do que em Haskell. O Haskell'sconcat
([[a]] -> [a]
) seria chamadoflatten
em Javascript e é implementado comofoldr (++) []
(Javascript:foldr(concat) ([])
assumindo funções ao curry). Javascriptconcat
é um anexo estranho ((++)
em Haskell), que pode lidar com ambos[a] -> [a] -> [a]
ea -> [a] -> [a]
.flatMap
, porque é exatamente issoconcatMap
: abind
instância dalist
mônada.concatpMap
é implementado comofoldr ((++) . f) []
. Traduzido em Javascript:const flatMap = f => foldr(comp(concat) (f)) ([])
. Naturalmente, isso é semelhante à sua implementação semcomp
.Uma solução para o caso mais geral, quando você pode ter alguns elementos que não são da matriz.
fonte
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)
ou istoflattenArrayOfArrays(arr, [1,[3]]);
- esses segundos argumentos são adicionados à saída.r
concatenará os resultados da recursão.Para nivelar uma matriz de matrizes de elemento único, você não precisa importar uma biblioteca, um loop simples é a solução mais simples e mais eficiente :
Para votantes negativos: leia a pergunta, não diminua o voto porque não se adequa ao seu problema muito diferente. Esta solução é a mais rápida e a mais simples para a pergunta feita.
fonte
['foo', ['bar']]
para['f', 'bar']
.Que tal usar o
reduce(callback[, initialValue])
método deJavaScript 1.8
Faria o trabalho.
fonte
[[1], [2,3]].reduce( (a,b) => a.concat(b), [] )
é mais sexy.[[1], [2,3]].reduce( (a,b) => a.concat(b))
Outra solução do ECMAScript 6 em estilo funcional:
Declare uma função:
e use-o:
Considere também uma função nativa Array.prototype.flat () (proposta para ES6) disponível nas últimas versões dos navegadores modernos. Obrigado a @ (Константин Ван) e @ (Mark Amery) o mencionaram nos comentários.
A
flat
função possui um parâmetro, especificando a profundidade esperada do aninhamento de matriz, que é igual1
por padrão.fonte
RangeError: Maximum call stack size exceeded
fonte
Observe: Quando
Function.prototype.apply
([].concat.apply([], arrays)
) ou o operador de dispersão ([].concat(...arrays)
) é usado para achatar uma matriz, ambos podem causar estouros de pilha para matrizes grandes, porque todos os argumentos de uma função são armazenados na pilha.Aqui está uma implementação segura para a pilha em estilo funcional que avalia os requisitos mais importantes entre si:
Assim que você se acostumar com pequenas funções de seta na forma de caril, composição de funções e funções de ordem superior, esse código será exibido como prosa. A programação consiste apenas em reunir pequenos blocos de construção que sempre funcionam como esperado, porque não contêm efeitos colaterais.
fonte
const flatten = (arr) => arr.reduce((a, b) => a.concat(b), []);
você economiza lixo visual e explicações para seus colegas de equipe por que você precisa de 3 funções extras e algumas chamadas de função também.Achatar uma linha ES6
Consulte achatamento de lodash , achatamento de sublinhado (raso
true
)ou
Testado com
Nivelamento profundo de uma linha ES6
Veja lodash flattenDeep , sublinhado flatten
Testado com
fonte
Array.prototype.concat.apply([], arr)
porque você cria uma matriz extra apenas para acessar aconcat
função. Os tempos de execução podem ou não otimizá-lo quando executados, mas o acesso à função no protótipo não parece mais feio do que isso já é em qualquer caso.Você pode usar
Array.flat()
comInfinity
qualquer profundidade da matriz aninhada.verifique aqui a compatibilidade do navegador
fonte
Uma abordagem haskellesca
fonte
ES6 maneira:
Maneira ES5 de
flatten
função com fallback ES3 para matrizes aninhadas N-times:fonte
Se você tiver apenas matrizes com 1 elemento de sequência:
fará o trabalho. Bt que corresponde especificamente ao seu exemplo de código.
fonte
['$4', ["$6"], ["$12"], ["$25"], ["$25", "$33", ['$45']]].join(',').split(',')
[1,4, [45, 't', ['e3', 6]]].toString().split(',')
---- ----- ou[1,4, [45, 't', ['e3', 6], false]].toString().split(',')
(Estou apenas escrevendo isso como uma resposta separada, com base no comentário de @danhbear.)
fonte
Eu recomendo uma função de gerador com economia de espaço :
Se desejar, crie uma matriz de valores nivelados da seguinte maneira:
fonte
...
para percorrer o gerador.Prefiro transformar toda a matriz, como está, em uma string, mas, ao contrário de outras respostas, faria isso usando
JSON.stringify
e não usando otoString()
método, que produz um resultado indesejado.Com essa
JSON.stringify
saída, tudo o que resta é remover todos os colchetes, envolver o resultado com os colchetes de início e final mais uma vez e servir o resultado com oJSON.parse
qual a string volta à "vida".fonte
["345", "2", "3,4", "2"]
em vez de separar cada um desses valores para separar índices"3,4"
.Você também pode tentar o novo
Array.Flat()
método. Funciona da seguinte maneira:O
flat()
método cria uma nova matriz com todos os elementos da sub-matriz concatenados nela recursivamente até a 1 camada de profundidade (ou seja, matrizes dentro de matrizes)Se você também deseja achatar matrizes tridimensionais ou dimensionais mais altas, basta chamar o método flat várias vezes. Por exemplo (3 dimensões):
Seja cuidadoso!
Array.Flat()
O método é relativamente novo. Navegadores mais antigos, como por exemplo, podem não ter implementado o método. Se você deseja que o código funcione em todos os navegadores, pode ser necessário transpilar seu JS para uma versão mais antiga. Verifique os documentos da web do MD para obter a compatibilidade atual do navegador.fonte
Infinity
argumento Assim:arr.flat(Infinity)
Usando o operador spread:
fonte
Isso não é difícil, basta percorrer as matrizes e mesclá-las:
fonte
Parece que isso parece um trabalho para RECURSION!
Código:
Uso:
fonte
flatten(new Array(15000).fill([1]))
lancesUncaught RangeError: Maximum call stack size exceeded
e congelado meus DevTools por 10 segundosEu fiz isso usando recursão e fechamentos
fonte
Eu estava brincando com os ES6 Generators outro dia e escrevi essa essência . Que contém ...
Basicamente, estou criando um gerador que faz um loop na matriz de entrada original; se encontrar uma matriz, ele usa o operador yield * em combinação com a recursão para nivelar continuamente as matrizes internas. Se o item não for uma matriz, apenas produzirá o único item. Em seguida, usando o operador ES6 Spread (também conhecido como operador splat), aplico o gerador em uma nova instância de array.
Não testei o desempenho disso, mas acho que é um bom exemplo simples de uso de geradores e do operador yield *.
Mas, novamente, eu estava apenas brincando, então tenho certeza de que existem maneiras mais eficazes de fazer isso.
fonte
apenas a melhor solução sem lodash
fonte