Matrice inversa in Javascript senza mutare la matrice originale


190

Array.prototype.reverse inverte il contenuto di un array in atto (con mutazione) ...

Esiste una strategia altrettanto semplice per invertire un array senza alterare il contenuto dell'array originale (senza mutazione)?



Ecco un benchmark che confronta le diverse opzioni: jsben.ch/HZ7Zp
Solomon

Risposte:


377

È possibile utilizzare slice () per effettuare una copia poi invertire () è

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


Potete per favore spiegare slice () senza parametri?
Alex

3
@Alex slice - If begin is omitted, slice begins from index 0.- quindi è lo stesso diarray.slice(0)
Arun P Johny

2
Penso che @Alex volesse dire "spiegalo nella tua risposta" ... a prescindere ... Soluzione brillante. Grazie!
sfletche,

14
NON consiglierei di usare questo approccio, perché è una pratica molto fuorviante. È molto confuso quando si utilizza slice () e in realtà non si taglia nulla. Se è necessario il contrario immutabile, basta creare una nuova copia nuova: const newArray = [... array] .reverse ()
Oleg Matei

105

In ES6:

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

2
In che modo la performance di questo si confronta con quella della risposta accettata? Sono gli stessi?
Katie,

@ Katie Molto simile, entrambi molto veloci, con Chrome che sembra dare [...].reverseun vantaggio in un caso di test molto semplice. jsperf.com/reverse-vs-slice-reverse/1
Brian M. Hunt

4
Sto diventando sempre .slicepiù veloce.
James Coyle,

3
@JamesCoyle Probabilmente dipende dal browser e dal sistema operativo, ma sliceè probabile che sia più veloce in quanto [...]è un iterable-to-array generico, quindi non può fare altrettante ipotesi. Inoltre, è probabile che slicesia meglio ottimizzato in b / c che sia in circolazione da molto tempo.
Brian M. Hunt,

I miei pensieri esattamente.
James Coyle,

11

Un'altra variante ES6:

Possiamo anche usare .reduceRight()per creare un array invertito senza effettivamente invertirlo.

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

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

console.log(B);

Risorse utili:


2
reduceRightè lento af
Dragos Rizescu il

@DragosRizescu Puoi condividere alcuni risultati dei test di esempio?
Mohammad Usman,

1
Ecco un repository con cui puoi giocare: (non il miglior esempio, ma ho avuto questo argomento con qualcuno qualche tempo fa in un contesto React, quindi l'ho messo insieme): github.com/rizedr/reduce-vs-reduceRight
Dragos Rizescu,

4
(a, c) => a.concat([c])sembra più idiomatico di(a, c) => (a.push(c), a)
Kyle Lin il

1
@DragosRizescu sembra che questa sia la più veloce delle 3 risposte migliori. jsperf.com/reverse-vs-slice-reverse/3
DBosley

7

Prova questa soluzione ricorsiva:

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
Sembra che si rompa per array vuoti.
Matthias,

6

Un'alternativa ES6 usando .reduce()e diffondendo.

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

Fondamentalmente quello che fa è creare un nuovo array con l'elemento successivo in foo e diffondere l'array accumulato per ogni iterazione dopo b.

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

In alternativa, .reduceRight()come menzionato sopra qui, ma senza la .push()mutazione.

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

4

Esistono diversi modi per invertire un array senza modificarlo. Due di loro lo sono

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

Test delle prestazioni http://jsben.ch/guftu


0

INTO Javascript semplice:

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

  return newArray;
}

0

Inversione in atto con scambio variabile solo a scopo dimostrativo (ma è necessaria una copia se non si desidera mutare)

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
Benvenuto in SO, Radion! Quando lasci una risposta, in genere è una buona idea spiegare perché la tua risposta funziona e perché sei arrivato a questa conclusione, questo aiuta gli utenti più nuovi a comprendere le interazioni e le lingue che hai specificato.
Ethan Field,

A difesa di Radion: P che 1alla fine avrebbe potuto essere qualcosa di più grande di zero, perché è così che funziona il Array.prototype.sortcallback (o cosiddetto compare function). In sostanza si confrontano sempre 2 numeri e in questo caso il confronto restituisce sempre positivi così si dice sempre passare il secondo numero davanti al primo :) questo è molto esplicativo: stackoverflow.com/questions/6567941/...
iulial

8
sort()muta l'array (cioè lo ordina in posizione), che è ciò che l'OP vuole evitare.
Clint Harris,

5
Questa risposta è sbagliata in diversi modi. (1) muta l'array, come sottolinea @ClintHarris, quindi non è meglio di .reverse (). (2) il tuo comparatore è illegale-- quando si restituisce 1 per a, b, è necessario restituire un numero negativo per b, a. Se la tua risposta inverte l'array su alcune implementazioni, è completamente per fortuna.
Don Hatch,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.