Comment échanger deux variables en JavaScript


Réponses:


321

Voici une ligne unique pour permuter les valeurs de deux variables.
Données variables aet b:

b = [a, a = b][0];

Démonstration ci-dessous:

var a=1,
    b=2,
    output=document.getElementById('output');

output.innerHTML="<p>Original: "+a+", "+b+"</p>";

b = [a, a = b][0];

output.innerHTML+="<p>Swapped: "+a+", "+b+"</p>";
<div id="output"></div>


264
+1. Mais la version la plus courte sera en ECMAScript 6: [a, b] = [b, a];.
dfsq

8
@Kay: Il semble également être beaucoup plus lent d'utiliser un tableau au lieu d'une troisième variable: http://jsperf.com/swap-array-vs-variable Je n'ai testé cela que dans Chrome. Je n'ai pas encore pu tester la version ECMAScript 6 car elle donne actuellement une Invalid left-hand side in assignment erreur.
Non

2
@ FrançoisWahl Bon point. Je pense que la plupart des réponses ici fonctionneront et sont assez équivalentes. Je suppose que c'est un compromis entre l'utilisation variable temporaire, la quantité de code et la vitesse.
showdev

3
@ FrançoisWahl eh bien, je n'aurais pas deviné que cette solution était tellement plus lente. Voir aussi: jsperf.com/swap-array-vs-variable/3
kay - SE is evil

3
@showdev Lisez la citation de Dijkstra dans la réponse de Ted Hopp.
Brian McCutchon

185

ES6 (Firefox et Chrome le prennent déjà en charge (Destructuring Assignment Array Matching)):

let a = 5, b = 6;
[a, b] = [b, a];
console.log(`${a} ${b}`);


2
quelqu'un connaît le nom d'un tel type d'échange dans es6?
derek

6
@derek - Je pense que cela s'appelle la correspondance de tableaux , une forme d' affectation de déstructuration .
Ted Hopp

4
Cela semble être environ 35 fois plus lent que la méthode de la troisième variable sur nodejs 7.4.0 / win7 64. Mais c'est sûr.
mkey


5
Depuis la version 6.8 de la V8, l'échange de variables avec la déstructuration des tableaux doit être aussi rapide qu'avec une variable temporaire ( v8project.blogspot.com/2018/06/v8-release-68.html ).
Ruben Verborgh

120

Tu peux le faire:

var a = 1,
    b = 2,
    tmp;
tmp = a;
a = b;
b = tmp;

Pour la lisibilité et la maintenabilité, cela est imbattable (du moins en JavaScript). Quiconque maintient le code (y compris vous dans six mois) saura exactement ce qui se passe.

Comme ce sont des nombres entiers, vous pouvez également utiliser n'importe quel nombre d'astuces intelligentes 1 pour permuter sans utiliser une troisième variable. Par exemple, vous pouvez utiliser l'opérateur xor au niveau du bit:

let a = 1, b = 2;
a = a ^ b;
b = a ^ b;
a = a ^ b;
    
console.log('a is now:', a);
console.log('b is now:', b);

C'est ce qu'on appelle l'algorithme d'échange XOR. Sa théorie de fonctionnement est décrite dans cet article de Wikipédia .

1 « Le programmeur compétent est pleinement conscient de la taille limitée de son propre crâne. Il se rapproche donc sa tâche avec humilité pleine et évite des tours intelligentes comme la peste. » - Edsger W. Dijkstra


Xor fonctionnera avec n'importe quel type de données. C'est l'astuce de soustraction qui ne fonctionnera qu'avec des nombres.
Rob Grant

11
@RobertGrant - L'opérateur xor dans JavaScript convertit ses opérandes en entiers 32 bits (en utilisant la ToInt32méthode interne - voir la section 11.10 du standard ECMAScript ). Il ne produit pas les résultats corrects pour les valeurs numériques non entières. Il convertit également les valeurs non numériques en entiers 32 bits. Si vous commencez par a = "hi"et b = "there", vous vous retrouvez avec a == 0et b == 0.
Ted Hopp

1
Cette astuce fonctionne avec n'importe quel type de données, à condition que cela ne vous dérange pas un résultat entier; les valeurs sont automatiquement converties en int32s. Cela signifie qu'il peut fonctionner avec des chaînes numériques, des booléens (0/1), des valeurs nulles (0) et des tableaux / objets vides (0). Bien que le type d'origine ne soit pas conservé, les booléens affectés ne fonctionneraient pas avec typeof a == 'boolean'ou a === false, par exemple. Les nombres réels fonctionnent, sauf qu'ils sont arrondis vers zéro et arrondis à l'entier le plus proche.
Beejor

1
@Beejor - En d'autres termes, cela fonctionne avec n'importe quel type de données, sauf que ce n'est pas le cas (sauf s'il s'agit de valeurs entières). Dans mon livre, "swap" signifie "terminer avec chaque variable ayant la valeur que l'autre avait", et non "convertir en int32 puis swap".
Ted Hopp

@TedHopp Très bien. Je voulais dire "fonctionne" en ce sens que vous pouvez lancer n'importe quel type de données, pas comme cela fonctionne comme une bonne solution de swap. Je suis d'accord que ce n'est pas très utile en général.
Beejor

58

N'utilisez pas le code ci-dessous. Ce n'est pas la méthode recommandée pour permuter les valeurs de deux variables ( utilisez simplement une variable temporaire pour cela). Cela montre juste une astuce JavaScript.

Cette solution n'utilise aucune variable temporaire, aucun tableau, un seul ajout et c'est rapide . En fait, c'est parfois plus rapide qu'une variable temporaire sur plusieurs plateformes .
Il fonctionne pour tous les nombres, ne déborde jamais et gère les cas extrêmes tels que Infinity et NaN.

a = b + (b=a, 0)

Cela fonctionne en deux étapes:

  • (b=a, 0)définit bl'ancienne valeur de aet donne0
  • a = b + 0définit al'ancienne valeur deb

5
La version temp var est légèrement plus rapide, plus générale et plus lisible également. jsperf.com/swap-two-numbers-without-tmp-var/9
Antimoine

Que signifie même cette syntaxe ()? comment donne-t-il 0?
Pete Alvin

8
L'opérateur entre parenthèses est l'opérateur virgule ,, et il a été encapsulé pour définir la priorité à droite. L'opérateur virgule évalue ses deux arguments (dans ce cas b=aet 0) et renvoie le dernier (dans ce cas 0). Donc ici, cela a pour effet de remettre le nouveau bà l'ancienne valeur de a, tout en cédant 0.
Ruben Verborgh

6
Ai-je raison de penser que cela ne fonctionne que pour la valeur numérique? Vous ne pouvez pas utiliser ceci avec par exemple var a = "hello" b = "world" comme a = "world0".
Chris GW Green

3
@ChrisGWGreen:a = b + (b=a, "")

19

Depuis ES6, vous pouvez également permuter les variables de manière plus élégante:

var a = 1,
    b = 2;

[a, b] = [b, a];

console.log('a:', a, 'b:', b); // a: 2 b: 1

18

Voici un one-liner, supposant aet bexistant déjà et ayant des valeurs à échanger:

var c=a, a=b, b=c;

Comme @Kay l'a mentionné, cela fonctionne en fait mieux que le mode tableau (presque 2x plus rapide).


1
Comme ma réponse idéale, je préfère simplement ne pas redéclarer les variables a et b lors de l'échange, et utiliser le nom de variable explicite "tmp". Comme var a, b, tmp; a = 1:; b = 2; tmp=a, a=b, b=tmp; Goût personnel.
Johnny Wong

10

Utilisez une troisième variable comme celle-ci:

var a = 1,
    b = 2,
    c = a;

a = b; // must be first or a and b end up being both 1
b = c;

DEMO - Utilisation d'une troisième variable



10

Méthode ES6 +: depuis ES6, vous pouvez permuter les variables plus élégamment. Vous pouvez utiliser la correspondance de tableau d'affectation de déstructuration. C'est tout simplement. var a = 10 b = 20;

[a, b] = [b, a]

console.log (a, b) // 20 10


10

Vous pouvez maintenant enfin faire:

let a = 5;
let b = 10;

[a, b] = [b, a]; // ES6

console.log(a, b);


9

Vous pouvez utiliser une variable d'échange temporaire ou XOR.

a = a ^ b
b = a ^ b
a = a ^ b

Ceci est juste un concept logique de base et fonctionne dans toutes les langues prenant en charge le fonctionnement XOR.

modifier: voir les commentaires. J'ai oublié de dire que cela ne fonctionne à coup sûr qu'avec un entier. Supposé les variables entières du fil de discussion de la question


16
Fonctionne pour la programmation d'entrevues et d'autres cas de questions générales. Notez cependant que c'est une façon plutôt stupide d'échanger des valeurs dans la vraie vie. D'une part, dans JS, cela ne fonctionne qu'avec des entiers.
cHao

1
@Kay Que voulez-vous dire par "pas une chose réelle depuis 30 ans?" J'utilise des opérateurs binaires chaque fois que cela a du sens, ce qui est en fait assez souvent (basculer un booléen inconnu, par exemple)
Ben Harold

1
L'opérateur @cHao Bitwise est systématiquement (et de loin) le plus rapide sur ma machine: jsperf.com/swap-array-vs-variable/2
Ben Harold

3
@php_surgeon J'ai un peu changé le violon pour que le compilateur ne puisse pas marquer les variables comme mortes. jsperf.com/swap-array-vs-variable/3 . La solution temp var est maintenant 1/4 plus rapide que la solution d'échange xor
kay - SE is evil

1
@Kay Dans les situations où quelque chose est stable, bien commenté, la technique la plus rapide et utilisé à un ou deux endroits seulement, je ne vois pas pourquoi ce ne serait pas bien dans le code de production. Les opérations au niveau du bit en général sont un concept difficile, donc si le code en utilise déjà un certain nombre, les responsables devraient de toute façon les connaître. Dans la plupart des cas, c'est évidemment exagéré. Je pense simplement que les déclarations générales ne sont pas toujours utiles; tout a sa place, même "goto" et "eval".
Beejor


7

Comme votre question était précieuse "Seulement ces variables, pas aucun objet.", La réponse sera également précieuse:

var a = 1, b = 2

a=a+b;
b=a-b;
a=a-b;

c'est un truc

Et comme l'a dit Rodrigo Assis, ça "peut être plus court"

 b=a+(a=b)-b;

Démo: http://jsfiddle.net/abdennour/2jJQ2/


1
Mêmes défauts que la réponse de @ DmiN.
kay - SE is evil

où trouvez-vous des défauts? Ce n'est pas honorable
Abdennour TOUMI

2
@AbdennourToumi Je pense que Kay fait référence au fait que votre réponse ne fonctionne qu'avec des entiers.
showdev

1
@showdev: Veuillez relire la question: "Seulement ces variables, pas des objets" .... ma réponse est précieuse comme question. Je vous demande de signaler le commentaire. Je le répète: ce n'est pas honorable.
Abdennour TOUMI

1
Cette conversation est bizarre. @AbdennourTOUMI - les variables ne sont pas les mêmes que les entiers. Vous pouvez avoir des variables qui pointent vers des objets, des chaînes, des fonctions, null, etc.
Rob Grant

6

Destructuration ES6:

À l'aide d'un tableau: [a, b] = [b, a]; // my favorite

Utilisation d'un objet: {a, b} = {a:b, b:a}; // not bad neither


4

Comment pourrions-nous manquer ces oneliners classiques

var a = 1, b = 2
a = ({a:b, _:(b=a)}).a;

Et

var a = 1, b = 2
a = (_=b,b=a,_);

Le dernier expose la variable globale '_' mais cela ne devrait pas avoir d'importance, car la convention javascript typique est de l'utiliser comme variable 'ne se soucie pas'.


1
Il y a une faute de frappe dans le second. Ça devrait êtrea = (_=b,b=a,_);
Mageek

Que signifie le trait de soulignement _? Pourquoi n'a-t-il pas besoin de déclaration?
jour

Le soulignement est simplement le nom de la variable globale, vous pouvez le remplacer par n'importe quel nom valide. par exemple a = (justsomething = b, b = a, justsomething)
Teemu Ikonen

6
Oh non, n'utilisez pas de variables globales magiques non déclarées! C'est un moyen sûr de bugs horribles dans la vraie vie.
oriadam

Quiconque utilise underscore.js sera très mécontent s'il essaie le second.
Ted Hopp

3

Je vois une sorte d'olympiade de programmation ici. Une autre solution en une ligne délicate:

b = (function(){ a=b; return arguments[0]; })(a);

Violon: http://jsfiddle.net/cherniv/4q226/


2
Pas besoin d'utiliser le slow arguments, faites-le b = (function (x){ return x; })(a, a=b).
Ruben Verborgh

1
@RubenVerborgh oui mais avec des arguments nous ne définissons pas une troisième variable!
Cherniv

1
Techniquement, la argumentsliste serait également une variable.
Ruben Verborgh

1
Eh bien, vous attribuez aà arguments[0]en passant comme paramètre.
Ruben Verborgh

1
@RubenVerborgh oui, mais vous ne créez pas le argumentset son assignation se fait "dans les coulisses"
Cherniv


3
var a = 5;
var b = 10;

b = [a, a = b][0];
//or
b = [a, a = b];
b = b[0];

//or
b = [a, b];
a = b[1];
b = b[0];


alert("a=" + a + ',' + "b=" + b);

supprimer ou commenter les 2 // ou et exécuter avec le seul ensemble de code

http://jsfiddle.net/USdv8/57/


2

Nous pouvons échanger des var comme ceci:

var val1 =  117,
    val2 = 327;

val2 = val1-val2; 
console.log(val2);
val1 = val1-val2;
console.log(val1);
val2 = val1+val2;
console.log(val2);

2

Dans ES6, il existe maintenant une affectation de déstructuration et vous pouvez faire:

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

1
let a = 2, b = 4;
[b, a] = [a, b];

une approche plus verbeuse serait

let a = 2, b = 4;
a = [a, b];
b = a[0];
a = a[1];


1

Jusqu'à ES5, pour échanger deux nombres, vous devez créer une variable temporaire, puis l'échanger. Mais dans ES6, il est très facile d'échanger deux nombres en utilisant la déstructuration des tableaux. Voir exemple.

let x,y;
[x,y]=[2,3];
console.log(x,y);      // return 2,3

[x,y]=[y,x];
console.log(x,y);      // return 3,2

1

Parce que j'entends que cette méthode fonctionne plus lentement:

b = [a, a = b][0];

Si vous prévoyez de stocker vos variables dans un objet (ou un tableau), cette fonction devrait fonctionner:

function swapVars(obj, var1, var2){
    let temp = obj[var1];
    obj[var1] = obj[var2];
    obj[var2] = temp;
}

Usage:

let test = {a: 'test 1', b: 'test 2'};

console.log(test); //output: {a: 'test 1', b: 'test 2'}

swapVars(test, 'a', 'b');

console.log(test); //output: {a: 'test 2', b: 'test 1'}

1

Nous pouvons utiliser l'IIFE pour échanger deux valeurs sans paramètre supplémentaire

var a = 5, b =8;
b = (function(a){ 
    return a 
}(a, a=b));

document.write("a: " + a+ "  b:  "+ b);


1

La déstructuration des tableaux ES6 est utilisée pour permuter deux variables. Voir exemple

var [x,y]=[1,2];
[x,y]=[y,x];

Une manière plus simple possible avec:

x === 1et y === 2; Mais après déstructuration, xest y, c'est 2-à- dire , et yest x, c'est-à-dire 1.


1

Swap en utilisant Bitwise

let a = 10;
let b = 20;
a ^= b;
y ^= a;
a ^= b;

Swap sur une seule ligne "à l'aide d'un tableau"

[a, b] = [b, a]

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.