Inverter matriz em Javascript sem alterar a matriz original


190

Array.prototype.reverse inverte o conteúdo de uma matriz no local (com mutação) ...

Existe uma estratégia igualmente simples para reverter uma matriz sem alterar o conteúdo da matriz original (sem mutação)?



Aqui está uma referência comparando as diferentes opções: jsben.ch/HZ7Zp
Solomon Ucko

Respostas:


377

Você pode usar o slice () para fazer uma cópia, em seguida, reverse () que

var newarray = array.slice().reverse();


Você pode explicar a fatia () sem parâmetros?
Alex

3
@Alex fatia - If begin is omitted, slice begins from index 0.- por isso, é o mesmo quearray.slice(0)
Arun P Johny

2
Acho que @Alex significava "explique na sua resposta" ... independentemente ... Solução brilhante. Obrigado!
precisa

14
Eu NÃO recomendaria usar essa abordagem, porque é uma prática muito enganadora. É muito confuso quando você usa slice () e realmente não corta nada. Se você precisa de inverter imutável, basta criar nova cópia fresca: const newArray = [... arranjo] .reverse ()
Oleg Matei

105

No ES6:

const newArray = [...array].reverse()

2
Como o desempenho disso se compara com o da resposta aceita? Eles são os mesmos?
Katie

@ Katie Muito parecido, ambos muito rápidos, com o Chrome parecendo dar [...].reverseuma vantagem em um caso de teste muito simples. jsperf.com/reverse-vs-slice-reverse/1
Brian M. Hunt

4
Estou constantemente ficando .slicesignificativamente mais rápido.
James Coyle

3
@JamesCoyle Provavelmente depende do navegador e do sistema operacional, mas sliceé provável que seja mais rápido , pois o b / c [...]é um iterável para matriz genérico, portanto não pode fazer tantas suposições. Além disso, é provável que sliceseja melhor otimizado porque já existe há muito tempo.
Brian M. Caça

Meus pensamentos exatamente.
James Coyle

11

Outra variante do ES6:

Também podemos usar .reduceRight()para criar uma matriz invertida sem realmente revertê-la.

let A = ['a', 'b', 'c', 'd', 'e', 'f'];

let B = A.reduceRight((a, c) => (a.push(c), a), []);

console.log(B);

Recursos úteis:


2
reduceRighté lento af
Dragos Rizescu

@DragosRizescu Você pode compartilhar alguns resultados de testes de amostra?
Mohammad Usman 26/03

1
Aqui está um repositório com o qual você pode jogar: (não é o melhor exemplo, mas teve esse argumento com alguém há um tempo atrás em um contexto React, portanto, eu o montei
Dragos Rizescu 27/03

4
(a, c) => a.concat([c])se sente mais idiomática que(a, c) => (a.push(c), a)
Kyle Lin

1
@DragosRizescu, na verdade, parece que essa é a mais rápida das 3 principais respostas. jsperf.com/reverse-vs-slice-reverse/3
DBosley

7

Experimente esta solução recursiva:

const reverse = ([head, ...tail]) => 
    tail.length === 0
        ? [head]                       // Base case -- cannot reverse a single element.
        : [...reverse(tail), head]     // Recursive case

reverse([1]);               // [1]
reverse([1,2,3]);           // [3,2,1]
reverse('hello').join('');  // 'olleh' -- Strings too!                              

1
Parece que ele quebraria para matrizes vazias.
Matthias

6

Uma alternativa ES6 usando .reduce()e espalhando.

const foo = [1, 2, 3, 4];
const bar = foo.reduce((acc, b) => ([b, ...acc]), []);

Basicamente, o que ele faz é criar uma nova matriz com o próximo elemento em foo e espalhar a matriz acumulada para cada iteração após b.

[]
[1] => [1]
[2, ...[1]] => [2, 1]
[3, ...[2, 1]] => [3, 2, 1]
[4, ...[3, 2, 1]] => [4, 3, 2, 1]

Alternativamente, .reduceRight()como mencionado acima aqui, mas sem a .push()mutação.

const baz = foo.reduceRight((acc, b) => ([...acc, b]), []);

4

Existem várias maneiras de reverter uma matriz sem modificar. Dois deles são

var array = [1,2,3,4,5,6,7,8,9,10];

// Using Splice
var reverseArray1 = array.splice().reverse(); // Fastest

// Using spread operator
var reverseArray2 = [...array].reverse();

// Using for loop 
var reverseArray3 = []; 
for(var i = array.length-1; i>=0; i--) {
  reverseArray.push(array[i]);
}

Teste de desempenho http://jsben.ch/guftu


0

INTO Javascript simples:

function reverseArray(arr, num) {
  var newArray = [];
  for (let i = num; i <= arr.length - 1; i++) {
    newArray.push(arr[i]);
  }

  return newArray;
}

0

Reversão no local com troca de variável apenas para fins demonstrativos (mas você precisa de uma cópia se não quiser fazer a mutação)

const myArr = ["a", "b", "c", "d"];
const copy = [...myArr];
for (let i = 0; i < (copy.length - 1) / 2; i++) {  
    const lastIndex = copy.length - 1 - i; 
    [copy[i], copy[lastIndex]] = [copy[lastIndex], copy[i]] 
}

-4

es6:

const reverseArr = [1,2,3,4].sort(()=>1)

4
Bem-vindo ao SO, Radion! Ao deixar uma resposta, normalmente é uma boa idéia explicar por que sua resposta funciona e por que você chegou a essa conclusão, isso ajuda os usuários mais novos a entender as interações e os idiomas especificados.
Ethan Field

Em defesa de Radion: P, que 1no final poderia ter sido maior que zero, porque é assim que o Array.prototype.sortretorno de chamada (ou o chamado compare function) funciona. Basicamente, você sempre compara 2 números e, nesse caso, a comparação retorna sempre positiva, por isso diz sempre mover para o segundo número na frente do primeiro :) isso é muito explicativo: stackoverflow.com/questions/6567941/…
dia

8
sort()modifica a matriz (ou seja, classifica-a no lugar), que é o que o OP deseja evitar.
Clint Harris

5
Esta resposta está errada de várias maneiras. (1) modifica a matriz, como aponta @ClintHarris, portanto não é melhor que .reverse (). (2) seu comparador é ilegal - quando você retorna 1 para a, b, você deve retornar um número negativo para b, a. Se sua resposta reverte a matriz em algumas implementações, é inteiramente por sorte.
Don Hatch
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.