Elementi dell'array di swap Javascript


228

Esiste un modo più semplice per scambiare due elementi in un array?

var a = list[x], b = list[y];
list[y] = a;
list[x] = b;

Risposte:


412

Hai solo bisogno di una variabile temporanea.

var b = list[y];
list[y] = list[x];
list[x] = b;

Modifica la risposta principale del dirottamento 10 anni dopo con molta adozione di ES6 sotto le nostre cinture:

Dato l'array arr = [1,2,3,4], ora puoi scambiare i valori in una riga in questo modo:

[arr[0], arr[1]] = [arr[1], arr[0]];

Ciò produrrebbe l'array [2,1,3,4]. Questo è un compito distruttivo .


2
Anche senza utilizzare ECMAScript 6 Destructuring Assignment, può effettivamente ottenere uno scambio simultaneo senza inquinare l'ambito corrente con una variabile temporanea: a = [b, b = a][0];come sottolineato da @Jan Anche se mi trovo ancora a utilizzare l'approccio variabile temporaneo in quanto è linguistico (ad esempio C / C ++ ) e il primo approccio che di solito mi viene in mente.
Ultimater,

3
Puoi scambiare sul posto (mutazione) con es6 come altri mostrano di seguito:[ list[y], list[x] ] = [ list[x], list[y] ];
protoEvangelion

[arr[0], arr[1]] = [arr[1], arr[0]]produce solo [2, 1]senza il resto dell'array
Yerko Palma

8
@YerkoPalma - l'espressione restituisce [2,1], ma l'array originale verrà mutato in [2,1,3,4]
danbars,

111

Se si desidera una singola espressione, utilizzando JavaScript nativo, ricordare che il valore restituito da un'operazione di giunzione contiene gli elementi che sono stati rimossi.

var A = [1, 2, 3, 4, 5, 6, 7, 8, 9], x= 0, y= 1;
A[x] = A.splice(y, 1, A[x])[0];
alert(A); // alerts "2,1,3,4,5,6,7,8,9"

Modificare:

Il [0]occorre alla fine dell'espressione quale Array.splice()restituisce una matrice, e in questa situazione si richiedono singolo elemento nell'array restituito.


3
splice restituisce un array. Quindi, nel tuo esempio, dopo l'operazione di scambio il tuo array in realtà assomiglia a: [[2], 1, 3, 4, 5, 6, 7, 8, 9]
JPot

1
A [x] = A.splice (y, 1, A [x]) [0]; ? in mootools Array.implement ({swap: function (x, y) {this [y] = this.splice (x, 1, this [y]) [0];}});
Ken,

Confermato, manca [0].
Johann Philipp Strathausen,

bello e breve, ma come diceva @aelgoa, quasi lento poi semplice scambio
ofir_aghai

75

Questo sembra ok ....

var b = list[y];
list[y] = list[x];
list[x] = b;

Uso di Howerver

var b = list[y];

significa che una variabile b sarà presente per il resto dell'ambito. Ciò può potenzialmente causare una perdita di memoria. Improbabile, ma ancora meglio da evitare.

Forse è una buona idea metterlo in Array.prototype.swap

Array.prototype.swap = function (x,y) {
  var b = this[x];
  this[x] = this[y];
  this[y] = b;
  return this;
}

che può essere chiamato come:

list.swap( x, y )

Questo è un approccio pulito sia per evitare perdite di memoria che a SECCO .


Mi piace anche questo. Array.implement ({swap: function (x, y) {x = this [x]; this [x] = this [y]; this [y] = x; return this;}});
Ken,

1
Questo è carino. Forse alcuni limiti controllando? Array.prototype.swap = function (x,y) { if (x >= 0 && x < this.length && y >= 0 && y < this.length) { var b = this[x]; this[x] = this[y]; this[y] = b; } return this; };
David R.,

@DavidR. Il controllo dei limiti è superfluo e non necessario. Il chiamante ha tutto il necessario per eseguire un tale controllo se lo si desidera, sebbene nella maggior parte dei casi si sappia già che x e y sono nei limiti perché ci si trova in un ciclo di qualche tipo.
Neil,

6
Non potresti evitare la "potenziale perdita di memoria" semplicemente avvolgendola in una funzione?
Carcigenicato,

3
Per evitare il potenziale incidente "appiattire", non toccherei la catena di prototipi di alcun tipo incorporato.
AaronDancer

55

Secondo una persona a caso su Metafilter , "Le versioni recenti di Javascript ti consentono di fare scambi (tra le altre cose) molto più ordinatamente:"

[ list[x], list[y] ] = [ list[y], list[x] ];

I miei test rapidi hanno dimostrato che questo codice Pythonic funziona alla grande nella versione di JavaScript attualmente utilizzata in "Google Apps Script" (".gs"). Purtroppo, ulteriori test mostrano che questo codice fornisce un "Errore di riferimento non rilevato: lato sinistro non valido nell'assegnazione." in qualunque versione di JavaScript (".js") è utilizzata da Google Chrome versione 24.0.1312.57 m.


2
Questo fa parte della proposta ES6: non è ancora formalizzato, quindi non dovrebbe essere assolutamente assunto che funzioni ovunque (sarebbe fantastico se lo facesse ...).
Isiah Meadows,

2
Funziona nell'ultima versione corrente di Firefox (39.0.3).
Jamie, l'

2
Funziona con la versione 54.0.2840.71 di Chrome e le versioni precedenti. Inoltre, questo dovrebbe essere il tuo codice da usare se usi un transpiler ES6 come Babel .
amebe

3
Adoro questa soluzione. Pulito, come previsto. Peccato che la domanda sia stata posta 9 anni fa ...
DavidsKanal

2
è stato standardizzato in es6 e questa funzione è chiamata destrutturazione.
AL-zami,

29

Bene, non è necessario bufferizzare entrambi i valori - solo uno:

var tmp = list[x];
list[x] = list[y];
list[y] = tmp;

13
il tuo 'tmp' sembra più ragionevole da usare rispetto a 'b'
mtasic85,

@ofir_aghai sì, hai ragione: 10+ anni fa, un'altra risposta è stata pubblicata 22 secondi prima di questa (12: 14: 16Z vs 12: 14: 38Z) ...
Marc Gravell

nei giorni normali, ero fedele a questo. ma solo perché la
seconda

mi dispiace non mi permetta di cambiare il voto .. "Il tuo voto ora è bloccato a meno che questa risposta non sia modificata"
ofir_aghai

22

È possibile scambiare elementi in un array nel modo seguente:

list[x] = [list[y],list[y]=list[x]][0]

Vedi il seguente esempio:

list = [1,2,3,4,5]
list[1] = [list[3],list[3]=list[1]][0]
//list is now [1,4,3,2,5]

Nota: funziona allo stesso modo per le variabili regolari

var a=1,b=5;
a = [b,b=a][0]

6
Questo è sorprendentemente simile al modo corretto standard per fare questo in ES6 (prossima versione di JavaScript): [list[x], list[y]] = [list[y], list[x]];.
Isiah Meadows,

1
Questo non ha nulla a che fare con lo scambio di array ES6 mediante la destrutturazione. Questo è solo un uso intelligente del flusso di lavoro di JS. Un bellissimo modello di scambio se usi frequentemente la codifica in linea, come ad esempiothis[0] > this[1] && (this[0] = [this[1],this[1]=this[0]][0]);
Redu,

18

Con valori numerici puoi evitare una variabile temporanea usando xor bit a bit

list[x] = list[x] ^ list[y];
list[y] = list[y] ^ list[x];
list[x] = list[x] ^ list[y];

o una somma aritmetica (osservando che funziona solo se x + y è inferiore al valore massimo per il tipo di dati)

list[x] = list[x] + list[y];
list[y] = list[x] - list[y];
list[x] = list[x] - list[y];

2
Quel darth è come in Vader? +1
krosenvold,

7
Qualcosa è sbagliato. Non list[y] = list[x] - list[x];equivale a list[y] = 0;?
ErikE

3
Il trucco xor fallisce anche quando x = y - imposta la lista [x] su zero, quando ci si potrebbe aspettare che mantenga la lista [x] il valore originale.
David Cary,

1
Tecnicamente si crea un valore temporaneo che non si sposta all'esterno dell'area pertinente dell'array.
Mark Smit,

1
Né più semplice, né più efficiente, né generico.
LoganMzz,

17

Questo non esisteva quando veniva posta la domanda, ma ES2015 introdusse l'array destructuring, permettendoti di scriverlo come segue:

let a = 1, b = 2;
// a: 1, b: 2
[a, b] = [b, a];
// a: 2, b: 1

14
Per scambiare in questo modo all'interno dell'array:[list[x], list[y]] = [list[y], list[x]];
Stromata

15

Per scambiare due elementi consecutivi di matrice

array.splice(IndexToSwap,2,array[IndexToSwap+1],array[IndexToSwap]);

13

Digest da http://www.greywyvern.com/?post=265

var a = 5, b = 9;    
b = (a += b -= a) - b;    
alert([a, b]); // alerts "9, 5"

1
Se lo avvolgi in una swap(a, b)funzione non devi preoccuparti della leggibilità.
AccidentalTaylorExpansion

1
Funziona solo per numeri interi
Redu,

Questo probabilmente ottimizza male. Un compilatore potrebbe rilevarlo come un "linguaggio di scambio", ma non può essere sicuro degli effetti a meno che non sia sicuro che entrambi i tipi siano ints e anche che non siano alias .
mwfearnley,

10

che dire di Destructuring_assignment

var arr = [1, 2, 3, 4]
[arr[index1], arr[index2]] = [arr[index2], arr[index1]]

che può anche essere esteso a

[src order elements] => [dest order elements]

9

Considera una soluzione del genere senza la necessità di definire la terza variabile:

function swap(arr, from, to) {
  arr.splice(from, 1, arr.splice(to, 1, arr[from])[0]);
}

var letters = ["a", "b", "c", "d", "e", "f"];

swap(letters, 1, 4);

console.log(letters); // ["a", "e", "c", "d", "b", "f"]

Nota: è possibile che si desideri aggiungere ulteriori controlli, ad esempio per la lunghezza dell'array. Questa soluzione è mutabile, quindi la swapfunzione non ha bisogno di restituire un nuovo array, ma fa solo una mutazione sull'array passato.


Inoltre, è possibile utilizzare l'operatore spread:arr.splice(from, 1, arr.splice(to, 1, ...arr[from]))
Orkun Tuzel,

7

Puoi scambiare qualsiasi numero di oggetti o letterali, anche di tipi diversi, usando una semplice funzione di identità come questa:

var swap = function (x){return x};
b = swap(a, a=b);
c = swap(a, a=b, b=c);

Per il tuo problema:

var swap = function (x){return x};
list[y]  = swap(list[x], list[x]=list[y]);

Funziona in JavaScript perché accetta argomenti aggiuntivi anche se non vengono dichiarati o utilizzati. Le assegnazioni a=becc. Si verificano dopo che aè stato passato alla funzione.


Hackish ... ma si poteva fare uno migliore, se si utilizza solo la funzione di una volta: list[y] = (function(x){return x})(list[x],list[x]=list[y]);. Oppure, se siete interessati a ES6 (prossima versione di JS), è incredibilmente facile: [list[x], list[y]] = [list[y], list[x]. Sono così felice che stiano aggiungendo alcuni aspetti più funzionali e di classe nella prossima versione di JavaScript.
Isiah Meadows,

6

Per due o più elementi (numero fisso)

[list[y], list[x]] = [list[x], list[y]];

Nessuna variabile temporanea richiesta!

Stavo pensando di chiamare semplicemente list.reverse().
Ma poi ho capito che avrebbe funzionato come swap solo quandolist.length = x + y + 1 .

Per numero variabile di elementi

Ho esaminato varie costruzioni Javascript moderne in questo senso, tra cui Map e map , ma purtroppo nessuna ha portato a un codice più compatto o più veloce di questa costruzione vecchio stile basata su loop:

function multiswap(arr,i0,i1) {/* argument immutable if string */
    if (arr.split) return multiswap(arr.split(""), i0, i1).join("");
    var diff = [];
    for (let i in i0) diff[i0[i]] = arr[i1[i]];
    return Object.assign(arr,diff);
}

Example:
    var alphabet = "abcdefghijklmnopqrstuvwxyz";
    var [x,y,z] = [14,6,15];
    var output = document.getElementsByTagName("code");
    output[0].innerHTML = alphabet;
    output[1].innerHTML = multiswap(alphabet, [0,25], [25,0]);
    output[2].innerHTML = multiswap(alphabet, [0,25,z,1,y,x], [25,0,x,y,z,3]);
<table>
    <tr><td>Input:</td>                        <td><code></code></td></tr>
    <tr><td>Swap two elements:</td>            <td><code></code></td></tr>
    <tr><td>Swap multiple elements:&nbsp;</td> <td><code></code></td></tr>
</table>


5

Esiste un modo interessante di scambiare:

var a = 1;
var b = 2;
[a,b] = [b,a];

(Modo ES6)


5
per un array, è di piùvar a= [7,8,9,10], i=2, j=3;[a[i],a[j]] = [a[j],a[i]];
caub

4
var a = [1,2,3,4,5], b=a.length;

for (var i=0; i<b; i++) {
    a.unshift(a.splice(1+i,1).shift());
}
a.shift();
//a = [5,4,3,2,1];

3

Ecco un one-liner che non muta list:

let newList = Object.assign([], list, {[x]: list[y], [y]: list[x]})

(Utilizza le funzionalità della lingua non disponibili nel 2009 quando è stata pubblicata la domanda!)


1

Ecco una versione compatta scambia valore a i1 con i2 in arr

arr.slice(0,i1).concat(arr[i2],arr.slice(i1+1,i2),arr[i1],arr.slice(i2+1))

Questo è meno efficiente del metodo variabile temporaneo. Stai effettivamente restituendo un array modificato che è stato tagliato tre volte e concatenato insieme a due oggetti tra i tre array tagliati. Hai effettivamente richiesto più del doppio della memoria del necessario per ottenere il valore da assegnare semplicemente all'array (nulla di tutto ciò è stato fatto in atto).
Isiah Meadows,

1

Ecco una variante che controlla innanzitutto se l'indice esiste nell'array:

Array.prototype.swapItems = function(a, b){
    if(  !(a in this) || !(b in this) )
        return this;
    this[a] = this.splice(b, 1, this[a])[0];
    return this;
}

Al momento restituirà solo thisse l'indice non esiste, ma è possibile modificare facilmente il comportamento in caso di errore


1

Scambia il primo e l'ultimo elemento in un array senza variabile temporanea o metodo di scambio ES6 [a, b] = [b, a]

[a.pop(), ...a.slice(1), a.shift()]


1

Soluzione dattiloscritta che clona l'array invece di mutare quello esistente

export function swapItemsInArray<T>(items: T[], indexA: number, indexB: number): T[] {
  const itemA = items[indexA];

  const clone = [...items];

  clone[indexA] = clone[indexB];
  clone[indexB] = itemA;

  return clone;
}

0

Solo per divertirci, un altro modo senza usare alcuna variabile aggiuntiva sarebbe:

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

// swap index 0 and 2
arr[arr.length] = arr[0];   // copy idx1 to the end of the array
arr[0] = arr[2];            // copy idx2 to idx1
arr[2] = arr[arr.length-1]; // copy idx1 to idx2
arr.length--;               // remove idx1 (was added to the end of the array)


console.log( arr ); // -> [3, 2, 1, 4, 5, 6, 7, 8, 9]


0

Per brevità, ecco la brutta versione da 1 linea che è solo leggermente meno brutta di tutto ciò che si concatena e affetta sopra. La risposta accettata è davvero la strada da percorrere e molto più leggibile.

Dato:

var foo = [ 0, 1, 2, 3, 4, 5, 6 ];

se si desidera scambiare i valori di due indici (a e b); allora questo lo farebbe:

foo.splice( a, 1, foo.splice(b,1,foo[a])[0] );

Ad esempio, se si desidera scambiare 3 e 5, è possibile farlo in questo modo:

foo.splice( 3, 1, foo.splice(5,1,foo[3])[0] );

o

foo.splice( 5, 1, foo.splice(3,1,foo[5])[0] );

Entrambi producono lo stesso risultato:

console.log( foo );
// => [ 0, 1, 2, 5, 4, 3, 6 ]

#splicehatersarepunks :)


0

Se non si desidera utilizzare la variabile temp in ES5, questo è un modo per scambiare elementi dell'array.

var swapArrayElements = function (a, x, y) {
  if (a.length === 1) return a;
  a.splice(y, 1, a.splice(x, 1, a[y])[0]);
  return a;
};

swapArrayElements([1, 2, 3, 4, 5], 1, 3); //=> [ 1, 4, 3, 2, 5 ]

In questo modo, invece di creare una variabile temporanea, si stanno creando 2 nuovi array poiché a.splicerestituisce un array con gli elementi rimossi. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
XCS

C'è un modo in cui possiamo farlo meglio? @Cristy
venkat7668

La risposta accettata è semplice. Questo sarà utile quando si ha una limitazione sul numero di variabili dichiarate (principalmente scopo dell'intervista :)). Ma non memoria efficiente come hai detto. @Cristy
venkat7668,

Personalmente penso che sia una cattiva pratica e non dovrebbe essere raccomandato ai principianti. È anche molto difficile da leggere.
XCS

0

prova questa funzione ...

$(document).ready(function () {
        var pair = [];
        var destinationarray = ['AAA','BBB','CCC'];

        var cityItems = getCityList(destinationarray);
        for (var i = 0; i < cityItems.length; i++) {
            pair = [];
            var ending_point = "";
            for (var j = 0; j < cityItems[i].length; j++) {
                pair.push(cityItems[i][j]);
            }
            alert(pair);
            console.log(pair)
        }

    });
    function getCityList(inputArray) {
        var Util = function () {
        };

        Util.getPermuts = function (array, start, output) {
            if (start >= array.length) {
                var arr = array.slice(0);
                output.push(arr);
            } else {
                var i;

                for (i = start; i < array.length; ++i) {
                    Util.swap(array, start, i);
                    Util.getPermuts(array, start + 1, output);
                    Util.swap(array, start, i);
                }
            }
        }

        Util.getAllPossiblePermuts = function (array, output) {
            Util.getPermuts(array, 0, output);
        }

        Util.swap = function (array, from, to) {
            var tmp = array[from];
            array[from] = array[to];
            array[to] = tmp;
        }
        var output = [];
        Util.getAllPossiblePermuts(inputArray, output);
        return output;
    }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


0

var arr = [1, 2];
arr.splice(0, 2, arr[1], arr[0]);
console.log(arr); //[2, 1]


1
Sebbene questo frammento di codice possa risolvere la domanda, inclusa una spiegazione aiuta davvero a migliorare la qualità del tuo post. Ricorda che stai rispondendo alla domanda per i lettori in futuro e quelle persone potrebbero non conoscere i motivi del tuo suggerimento sul codice.
Alessio,

-1

Usando ES6 è possibile farlo in questo modo ...

Immagina di avere questi 2 array ...

const a = ["a", "b", "c", "d", "e"];
const b = [5, 4, 3, 2, 1];

e vuoi scambiare i primi valori:

const [a0] = a;
a[0] = b[0];
b[0] = a0;

e valore:

a; //[5, "b", "c", "d", "e"]
b; //["a", 4, 3, 2, 1]

-2
Array.prototype.swap = function(a, b) {
  var temp = this[a];
  this[a] = this[b];
  this[b] = temp;
};

Uso:

var myArray = [0,1,2,3,4...];
myArray.swap(4,1);

1
Non c'è bisogno di essere scortesi. Inoltre, l'estensione del Arrayprototipo non faceva parte di ciò che era stato chiesto: potrebbe confondere più di quanto non faccia bene.
Mathias Lykkegaard Lorenzen,

Come sta esprimendo che alcune delle risposte sono pazze e l'estensione del prototipo dell'array sarebbe e aggiungendo un ritorno questo lo renderebbe in grado di ...
user2472643

2
Lo stai esprimendo come "il modo corretto". Potrebbe dare l'impressione sbagliata. Invece, suggerirei di menzionare ciò che stai facendo (estendere il prototipo) e come è utile, esattamente come mi hai appena descritto.
Mathias Lykkegaard Lorenzen,

1
capito, scusa il mio equilibrio non è in coppia a volte ^ _ ^
user2472643

2
Sei l'unico a descrivere un problema con il contesto della risposta ... prima di tutto i punteggi negativi dovrebbero essere riservati per le risposte non funzionanti. In secondo luogo, questa è una buona risposta con un uso elegante che non causa conflitti. Giudica il codice non la consegna. Anche nella mia risposta se lo hai rimosso ed escluso l'estensione del prototipo, diventa esattamente lo stesso della risposta più votata, quindi il fatto che questo sia -6 mostra la mancanza di pensiero da parte delle persone che lo hanno votato. Ed è stato pubblicato mesi prima della risposta migliore ... quindi sembra una popolarità non un contest di codice.
user2472643

-3

Se necessario, scambiare solo il primo e l'ultimo elemento:

array.unshift( array.pop() );

Questo codice è difettoso. Prende l'ultimo elemento dell'array e lo mette all'inizio, che non si scambia. Questo codice fa questo: [1, 2, 3] => [3, 1, 2]invece di [1, 2, 3] => [3, 2, 1].
David Archibald,
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.