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>

showdev
la source
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}`);

Pedro Justo
la source
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

Ted Hopp
la source
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
Ruben Verborgh
la source
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
Peter
la source
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).

bobobobo
la source
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


Nan
la source
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

Jalak Patoliya
la source
10

Vous pouvez maintenant enfin faire:

let a = 5;
let b = 10;

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

console.log(a, b);

mehulmpt
la source
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

DmiN
la source
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/

Abdennour TOUMI
la source
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

Flavien Volken
la source
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'.

Teemu Ikonen
la source
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/

Tcherniv
la source
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

Échange de ligne unique

a = a^b^(b^=(a^b));
Saruselvi
la source
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/

Thilak Raj
la source
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);
Mohammed Javed
la source
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
Stanislav Bozhanov
la source
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];
Enogwe Victor
la source
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
Avinash Malhotra
la source
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'}
SwiftNinjaPro
la source
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);

Ganesh Phirke
la source
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.

Krish Malhotra
la source
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]
HusseiELbadady
la source
-5

(fonction (A, B) {b = A; a = B;}) (parseInt (a), parseInt (b));

Carlos Correia
la source