Javascript-Swap-Array-Elemente

227

Gibt es eine einfachere Möglichkeit, zwei Elemente in einem Array auszutauschen?

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

Antworten:

409

Sie benötigen nur eine temporäre Variable.

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

Bearbeiten Sie die Entführung der Top-Antwort 10 Jahre später mit viel ES6-Akzeptanz:

In Anbetracht des Arrays arr = [1,2,3,4]können Sie die Werte jetzt wie folgt in einer Zeile austauschen:

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

Dies würde das Array erzeugen [2,1,3,4]. Dies ist eine Destrukturierungsaufgabe .

Tvanfosson
quelle
2
Auch ohne Verwendung von ECMAScript 6 Destructuring Assignment kann tatsächlich ein gleichzeitiger Austausch a = [b, b = a][0];erzielt werden, ohne den aktuellen Bereich mit einer temporären Variablen zu verschmutzen: wie von @Jan hervorgehoben. Obwohl ich immer noch den temporären Variablenansatz als sprachübergreifend verwende (z. B. C / C ++) ) und der erste Ansatz, der mir normalerweise in den Sinn kommt.
Ultimater
3
Sie können mit es6 an Ort und Stelle tauschen (mutieren), wie andere unten zeigen:[ list[y], list[x] ] = [ list[x], list[y] ];
ProtoEvangelion
[arr[0], arr[1]] = [arr[1], arr[0]]Produzieren Sie nur [2, 1]ohne den Rest des Arrays
Yerko Palma
7
@ YerkoPalma - der Ausdruck gibt [2,1] zurück, aber das ursprüngliche Array wird zu [2,1,3,4] mutiert
danbars
111

Wenn Sie einen einzelnen Ausdruck mit nativem Javascript verwenden möchten, denken Sie daran, dass der Rückgabewert einer Spleißoperation die Elemente enthält, die entfernt wurden.

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"

Bearbeiten:

Das [0]ist am Ende des Ausdrucks erforderlich, da es Array.splice()ein Array zurückgibt. In dieser Situation benötigen wir das einzelne Element im zurückgegebenen Array.

kennebec
quelle
3
Spleiß gibt ein Array zurück. In Ihrem Beispiel sieht Ihr Array nach dem Swap-Vorgang tatsächlich so aus: [[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
Bestätigt, die [0] fehlt.
Johann Philipp Strathausen
nett und kurz, aber wie @aelgoa sagte, fast langsam dann einfach tauschen
ofir_aghai
74

Das scheint in Ordnung zu sein ....

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

Wie auch immer mit

var b = list[y];

bedeutet, dass eine b- Variable für den Rest des Bereichs vorhanden sein wird. Dies kann möglicherweise zu einem Speicherverlust führen. Unwahrscheinlich, aber immer noch besser zu vermeiden.

Vielleicht eine gute Idee, dies in Array.prototype.swap einzufügen

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

was wie folgt genannt werden kann:

list.swap( x, y )

Dies ist ein sauberer Ansatz, um sowohl Speicherlecks als auch DRY zu vermeiden .

Stefan
quelle
Das gefällt mir auch. Array.implement ({swap: function (x, y) {x = this [x]; this [x] = this [y]; this [y] = x; return this;}});
Ken
1
Das ist nett. Vielleicht einige Grenzen überprüfen? 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. Die Überprüfung der Grenzen ist überflüssig und unnötig. Der Anrufer hat alles Notwendige, um eine solche Prüfung durchzuführen, wenn dies gewünscht wird. In den meisten Fällen wissen Sie jedoch bereits, dass x und y in Grenzen liegen, weil Sie sich in einer Schleife befinden.
Neil
6
Könnten Sie den "potenziellen Speicherverlust" nicht vermeiden, indem Sie ihn einfach in eine Funktion einschließen?
Carcigenicate
3
Um das mögliche "Abflachen" von Pannen zu vermeiden, würde ich die Prototypenkette von eingebauten Typen nicht berühren.
AaronDancer
54

Laut einer zufälligen Person auf Metafilter "können Sie in neueren Versionen von Javascript (unter anderem) viel sauberer Swaps durchführen:"

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

Meine schnellen Tests haben gezeigt, dass dieser Pythonic-Code in der Version von JavaScript, die derzeit in "Google Apps Script" (".gs") verwendet wird, hervorragend funktioniert. Leider zeigen weitere Tests, dass dieser Code einen "Nicht erfassten Referenzfehler: Ungültige linke Seite in Zuweisung" ergibt. in welcher Version von JavaScript (".js") von Google Chrome Version 24.0.1312.57 m verwendet wird.

David Cary
quelle
2
Dies ist Teil des ES6-Vorschlags: Es ist noch nicht formalisiert, daher sollte nicht unbedingt davon ausgegangen werden, dass es überall funktioniert (es wäre fantastisch, wenn es so wäre ...).
Isiah Meadows
2
Es funktioniert in der aktuellen Firefox-Version (39.0.3).
Jamie
2
Es funktioniert in Chrome Version 54.0.2840.71 und früheren Versionen. Dies sollte auch Ihr Code sein, wenn Sie einen ES6-Transpiler wie babel verwenden .
Amöbe
3
Ich liebe diese Lösung. Wie vorgesehen reinigen. Schade, dass die Frage vor 9 Jahren gestellt wurde ...
DavidsKanal
2
es wurde in es6 standardisiert und diese Funktion wird als Destrukturierung bezeichnet.
AL-Zami
29

Nun, Sie müssen nicht beide Werte puffern - nur einen:

var tmp = list[x];
list[x] = list[y];
list[y] = tmp;
Marc Gravell
quelle
13
Ihr 'tmp' klingt vernünftiger als 'b'
mtasic85
@ofir_aghai Ja, Sie haben Recht: Vor mehr als 10 Jahren wurde eine weitere Antwort 22 Sekunden vor dieser veröffentlicht (12: 14: 16Z vs 12: 14: 38Z) ...
Marc Gravell
am normalen tag blieb ich dabei. aber nur weil die Sekunden Ausgabe & Respekt Ihrer 10 Jahre hier wieder aufgenommen werden ;-)
ofir_aghai
Entschuldigung, ich kann die Abstimmung nicht ändern. "Ihre Abstimmung ist jetzt gesperrt, es sei denn, diese Antwort wird bearbeitet"
ofir_aghai
22

Sie können Elemente in einem Array folgendermaßen austauschen:

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

Siehe folgendes Beispiel:

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

Hinweis: Dies funktioniert für reguläre Variablen genauso

var a=1,b=5;
a = [b,b=a][0]
Jan.
quelle
6
Dies ähnelt auffallend der standardmäßigen korrekten Vorgehensweise in ES6 (nächste Version von JavaScript) : [list[x], list[y]] = [list[y], list[x]];.
Isiah Meadows
1
Dies hat nichts zu tun, wir ES6-Array-Swap durch De-Strukturierung. Dies ist nur eine clevere Verwendung des JS-Workflows. Ein schönes Swap-Muster, wenn Sie häufig Inline-Codierung verwenden, wie z. B.this[0] > this[1] && (this[0] = [this[1],this[1]=this[0]][0]);
Redu
18

Mit numerischen Werten können Sie eine temporäre Variable vermeiden, indem Sie bitweises xor verwenden

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

oder eine arithmetische Summe (wobei zu beachten ist, dass dies nur funktioniert, wenn x + y kleiner als der Maximalwert für den Datentyp ist)

list[x] = list[x] + list[y];
list[y] = list[x] - list[y];
list[x] = list[x] - list[y];
Jakub Arnold
quelle
2
Ist das Darth wie in Vader? +1
Krosenvold
7
Irgendwas stimmt nicht. Ist das nicht list[y] = list[x] - list[x];gleichbedeutend mit list[y] = 0;?
ErikE
3
Der xor-Trick schlägt auch fehl, wenn x = y - er setzt Liste [x] auf Null, wenn Sie erwarten können, dass Liste [x] den ursprünglichen Wert beibehält.
David Cary
1
Technisch gesehen erstellen Sie einen temporären Wert, den Sie jedoch nicht außerhalb des relevanten Bereichs des Arrays verschieben.
Mark Smit
1
Weder einfacher, noch effizienter, weder generisch.
LoganMzz
17

Dies war nicht vorhanden, als die Frage gestellt wurde, aber ES2015 führte die Array-Destrukturierung ein, sodass Sie sie wie folgt schreiben können:

let a = 1, b = 2;
// a: 1, b: 2
[a, b] = [b, a];
// a: 2, b: 1
dirkdig
quelle
14
Um so innerhalb des Arrays zu tauschen:[list[x], list[y]] = [list[y], list[x]];
Stromata
15

Zwei aufeinanderfolgende Elemente des Arrays austauschen

array.splice(IndexToSwap,2,array[IndexToSwap+1],array[IndexToSwap]);
Piyush Madan
quelle
13

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

var a = 5, b = 9;    
b = (a += b -= a) - b;    
alert([a, b]); // alerts "9, 5"
R-Weg Orz
quelle
1
Wenn Sie dies in eine swap(a, b)Funktion einbinden, müssen Sie sich keine Gedanken über die Lesbarkeit machen.
AccidentalTaylorExpansion
1
Funktioniert nur für ganze Zahlen
Redu
Dies optimiert wahrscheinlich schlecht. Ein Compiler erkennt es möglicherweise als "Swap-Idiom", kann sich jedoch der Auswirkungen nicht sicher sein, es sei denn, es kann sicher sein, dass beide Typen Ints sind und auch kein Alias .
mwfearnley
10

Was ist mit Destructuring_assignment?

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

die auch erweitert werden kann

[src order elements] => [dest order elements]
ROROROOROROR
quelle
9

Betrachten Sie eine solche Lösung, ohne die dritte Variable definieren zu müssen:

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

Hinweis: Möglicherweise möchten Sie zusätzliche Überprüfungen hinzufügen, z. B. für die Arraylänge. Diese Lösung ist veränderbar, sodass die swapFunktion kein neues Array zurückgeben muss, sondern nur eine Mutation über das übergebene Array.

Shevchenko Viktor
quelle
Als Ergänzung könnte auch ein Spread-Operator verwendet werden:arr.splice(from, 1, arr.splice(to, 1, ...arr[from]))
Orkun Tuzel
7

Mit einer einfachen Identitätsfunktion wie der folgenden können Sie eine beliebige Anzahl von Objekten oder Literalen, auch unterschiedlicher Art, austauschen:

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

Für Ihr Problem:

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

Dies funktioniert in JavaScript, da zusätzliche Argumente akzeptiert werden, auch wenn sie nicht deklariert oder verwendet werden. Die Zuweisungen a=busw. erfolgen, nachdem sie aan die Funktion übergeben wurden.

Dansalmo
quelle
Hackish ... aber Sie könnten es besser machen, wenn Sie die Funktion nur einmal verwenden : list[y] = (function(x){return x})(list[x],list[x]=list[y]);. Oder wenn Sie an ES6 (nächste Version von JS) interessiert sind, ist es wahnsinnig einfach : [list[x], list[y]] = [list[y], list[x]. Ich bin so froh, dass sie der nächsten Version von JavaScript einige weitere funktionale und klassenbasierte Aspekte hinzufügen.
Isiah Meadows
6

Für zwei oder mehr Elemente (feste Nummer)

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

Keine temporäre Variable erforderlich!

Ich dachte darüber nach, einfach anzurufen list.reverse().
Aber dann wurde mir klar, dass es nur dann als Tausch funktionieren würde list.length = x + y + 1.

Für variable Anzahl von Elementen

Ich habe verschiedene moderne Javascript-Konstruktionen zu diesem Zweck untersucht, einschließlich Map und Map , aber leider hat keine zu einem Code geführt, der kompakter oder schneller war als diese altmodische, schleifenbasierte Konstruktion:

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>

7vujy0f0hy
quelle
5

Es gibt eine interessante Art zu tauschen:

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

(ES6 Weg)

Vivek
quelle
5
Für ein Array ist es mehrvar 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];
Nathan Romano
quelle
3

Hier ist ein Einzeiler, der nicht mutiert list:

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

(Verwendet Sprachfunktionen, die 2009 nicht verfügbar waren, als die Frage gestellt wurde!)

fmg
quelle
1

Hier ist eine kompakte Version, die den Wert bei i1 gegen i2 in arr austauscht

arr.slice(0,i1).concat(arr[i2],arr.slice(i1+1,i2),arr[i1],arr.slice(i2+1))
user2044802
quelle
Das ist weniger effizient als die temporäre Variablenmethode. Sie geben effektiv ein modifiziertes Array zurück, das dreimal in Scheiben geschnitten und zusammen mit zwei Objekten zwischen den drei in Scheiben geschnittenen Arrays verkettet wurde. Sie haben effektiv mehr als das Doppelte des Speichers als erforderlich benötigt, um den Wert zu erhalten, der einfach dem Array zugewiesen werden soll (nichts davon wurde an Ort und Stelle durchgeführt).
Isiah Meadows
1

Hier ist eine Variante, die zuerst prüft, ob der Index im Array vorhanden ist:

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

Derzeit wird nur zurückgegeben, thiswenn der Index nicht vorhanden ist. Sie können das Verhalten jedoch bei einem Fehler leicht ändern

Douglas.Sesar
quelle
1

Tauschen Sie das erste und letzte Element in einem Array ohne temporäre Variable oder ES6-Swap-Methode aus [a, b] = [b, a]

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

gengns
quelle
1

Typoskript-Lösung, die das Array klont, anstatt das vorhandene zu mutieren

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;
}
pie6k
quelle
0

Nur zum Spaß wäre ein anderer Weg ohne zusätzliche Variable:

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]

vsync
quelle
0

Der Kürze halber ist hier die hässliche Einzeiler-Version, die nur geringfügig weniger hässlich ist als all das Concat und Slicing oben. Die akzeptierte Antwort ist wirklich der richtige Weg und lesbarer.

Gegeben:

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

wenn Sie die Werte zweier Indizes (a und b) tauschen möchten; dann würde das es tun:

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

Wenn Sie beispielsweise die 3 und 5 tauschen möchten, können Sie dies folgendermaßen tun:

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

oder

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

Beide ergeben das gleiche Ergebnis:

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

#splicehatersarepunks :)

Jasonovich
quelle
0

Wenn Sie in ES5 keine temporäre Variable verwenden möchten, können Sie auf diese Weise Array-Elemente austauschen.

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 ]
venkat7668
quelle
Auf diese Weise erstellen Sie anstelle einer temporären Variablen zwei neue Arrays, die a.spliceein Array mit den entfernten Elementen zurückgeben. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
XCS
Gibt es eine Möglichkeit, wie wir es besser machen können? @Cristy
venkat7668
Akzeptierte Antwort ist einfach. Dies ist praktisch, wenn die Anzahl der Variablendeklarationen begrenzt ist (hauptsächlich für Interviewzwecke :)). Aber nicht speichereffizient, wie Sie erwähnt haben. @Cristy
venkat7668
Ich persönlich halte es für eine schlechte Praxis und sollte Anfängern nicht empfohlen werden. Es ist auch sehr schwer zu lesen.
XCS
0

Probieren Sie diese Funktion aus ...

$(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>

bilal chaudhari
quelle
0

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

JATIN KUMAR NAYAK
quelle
1
Während dieses Code-Snippet die Frage lösen kann, hilft das Hinzufügen einer Erklärung wirklich, die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie die Frage für Leser in Zukunft beantworten und diese Personen möglicherweise die Gründe für Ihren Codevorschlag nicht kennen.
Alessio
-1

Mit ES6 ist das möglich ...

Stellen Sie sich vor, Sie haben diese 2 Arrays ...

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

und Sie möchten die ersten Werte tauschen:

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

und Wert:

a; //[5, "b", "c", "d", "e"]
b; //["a", 4, 3, 2, 1]
Alireza
quelle
-2
Array.prototype.swap = function(a, b) {
  var temp = this[a];
  this[a] = this[b];
  this[b] = temp;
};

Verwendung:

var myArray = [0,1,2,3,4...];
myArray.swap(4,1);
user2472643
quelle
1
Keine Notwendigkeit, unhöflich zu sein. Auch die Erweiterung des ArrayPrototyps war nicht Teil der Anforderungen - es kann mehr verwirren als nützen.
Mathias Lykkegaard Lorenzen
Wie drückt man aus, dass einige der Antworten verrückt sind und das Erweitern des Array-Prototyps wäre und das Hinzufügen einer Rückgabe würde es
verkettenfähig
2
Sie drücken es als "den richtigen Weg" aus. Es kann den falschen Eindruck erwecken. Stattdessen würde ich vorschlagen, zu erwähnen, was Sie tun (den Prototyp erweitern) und wie nützlich es ist, genau wie Sie es mir gerade beschrieben haben.
Mathias Lykkegaard Lorenzen
1
gotcha, sorry meine Haltung ist manchmal nicht zu
zweit
2
Sie sind der einzige, der ein Problem mit dem Kontext der Antwort beschreibt. Zunächst sollten negative Bewertungen für nicht funktionierende Antworten reserviert werden. Zweitens ist dies eine gute Antwort mit einer eleganten Verwendung, die keine Konflikte verursacht. Beurteilen Sie den Code, nicht die Lieferung. Auch in meiner Antwort, wenn Sie es abgespeckt und die Prototyp-Erweiterung ausgeschlossen haben, entspricht es genau der am häufigsten bewerteten Antwort. Die Tatsache, dass dies -6 ist, zeigt den Mangel an Gedanken der Leute, die es abgelehnt haben. Und wurde Monate vor der Top-Antwort gepostet ... das klingt also nach einer Popularität, nicht nach einem Code-Wettbewerb.
user2472643
-3

Bei Bedarf nur das erste und das letzte Element austauschen:

array.unshift( array.pop() );
Alex Moonlight
quelle
Dieser Code ist fehlerhaft. Es nimmt das letzte Element des Arrays und setzt es dann an den Anfang, das nicht ausgetauscht wird. Dieser Code macht das: [1, 2, 3] => [3, 1, 2]anstelle von [1, 2, 3] => [3, 2, 1].
David Archibald