356

Is there a simpler way to swap two elements in an array?

var a = list[x], b = list[y];
list[y] = a;
list[x] = b;
1
  • ES2023 Array Method with() you can do it in one line: list.with(x,list[y]).with(y,list[x]) see my answer with an example! Commented Jun 11, 2023 at 11:04

37 Answers 37

700

You only need one temporary variable.

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

Or with ES6 and later:

Given the array arr = [1,2,3,4], you can swap values in one line now like so:

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

This would produce the array [2,1,3,4]. This is destructuring assignment.

Sign up to request clarification or add additional context in comments.

8 Comments

Even without utilizing ECMAScript 6 Destructuring Assignment, can actually achieve a simultaneous swap without polluting the current scope with a temporary variable: a = [b, b = a][0]; as pointed out by @Jan Although I still find myself utilizing the temporary variable approach as it's cross-language (e.g. C/C++) and the first approach that usually pops into my mind.
You can swap in place (mutate) with es6 as others show below: [ list[y], list[x] ] = [ list[x], list[y] ];
@YerkoPalma - the expression returns [2,1], but the original array will be mutated to [2,1,3,4]
In that case the es6 expression is likely inefficient as it is generating a new and unnecessary array allocation.
Can someone explain to me why [arr[1], arr[0]] mutates the original array? This seems incredible unreadable to me.
|
136

If you want a single expression, using native JavaScript, remember that the return value from a splice operation contains the element(s) that was removed.

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"

The [0] is necessary at the end of the expression as Array.splice() returns an array, and in this situation we require the single element in the returned array.

6 Comments

splice returns an array. So in your example, after the swap operation your array actually looks like: [[2], 1, 3, 4, 5, 6, 7, 8, 9]
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]; } });
Confirmed, the [0] is missing.
nice and short, but as @aelgoa said, almost slow then simple swap
with 1 character less [A[x]] = A.splice(y, 1, A[x]) !
|
90

According to some random person on Metafilter, "Recent versions of Javascript [sic] allow you to do swaps (among other things) much more neatly:"

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

My quick tests showed that this Pythonic code works great in the version of JavaScript currently used in "Google Apps Script" (".gs"). Alas, further tests show this code gives a "Uncaught ReferenceError: Invalid left-hand side in assignment." in whatever version of JavaScript (".js") is used by Google Chrome Version 24.0.1312.57 m.

6 Comments

This is part of the ES6 proposal: it's not formalized yet, thus it shouldn't be absolutely assumed to work everywhere (it would be awesome if it did...).
It works in the current firefox latest version (39.0.3).
It works in Chrome Version 54.0.2840.71 and earlier Versions. Also, this should be your got-to code if you use a ES6 transpiler such as babel.
Love this solution. Clean, as intended. Too bad the question was asked 9 years ago...
it has been standardized in es6 and this feature is called destructuring.
|
82

This seems ok....

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

Howerver using

var b = list[y];

means a b variable is going to be to be present for the rest of the scope. This can potentially lead to a memory leak. Unlikely, but still better to avoid.

Maybe a good idea to put this into Array.prototype.swap

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

which can be called like:

list.swap( x, y )

This is a clean approach to both avoiding memory leaks and DRY.

7 Comments

I like this also. Array.implement({ swap: function(x,y) { x = this[x]; this[x] = this[y]; this[y] = x; return this; } });
This is nice. Maybe some bounds checking? 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; };
@DavidR. Bounds checking is superfluous and unnecessary. The caller has everything necessary to perform such a check if that is desired, though in most cases you already know x and y are in bounds because you're in a loop of some sort.
Couldn't you avoid the "potential memory leak" by just wrapping it in a function?
To avoid the potential "flatten" mishap, I wouldn't touch the prototype chain of any built-in types.
|
33

Well, you don't need to buffer both values - only one:

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

4 Comments

your 'tmp' sounds more reasonable to use then 'b'
@ofir_aghai yes, you're right: 10+ years ago, another answer was posted 22 seconds before this one (12:14:16Z vs 12:14:38Z)...
in regular day, i was stick with it. but just because the seconds issue & respect of your 10 years resume here ;-)
sorry it doesnt let me to change the vote.."Your vote is now locked in unless this answer is edited"
28

You can swap elements in an array the following way:

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

See the following example:

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

Note: it works the same way for regular variables

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

2 Comments

This is strikingly similar to the standard correct way to do this in ES6 (next version of JavaScript): [list[x], list[y]] = [list[y], list[x]];.
This has got nothing to do we ES6 array swap by de-structuring. This is just a clever use of JS workflow. A beautiful swap pattern if you use inline coding frequently, such as this[0] > this[1] && (this[0] = [this[1],this[1]=this[0]][0]);
23

ES2015 (ES6) introduced array destructuring, allowing you to write it as follows:

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

1 Comment

To swap like this inside the array: [list[x], list[y]] = [list[y], list[x]];
21

Consider such a solution without a need to define the third variable:

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

Note: You may want to add additional checks for example for array length. This solution is mutable so swap function does not need to return a new array, it just does mutation over array passed into.

3 Comments

As an addition, spread operator could also be used: arr.splice(from, 1, arr.splice(to, 1, ...arr[from]))
this is what I was looking for, thank you
But it does create two new arrays
18

With numeric values you can avoid a temporary variable by using bitwise XOR:

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

Or an arithmetic sum (noting that this only works if x + y is less than the maximum value for the data type):

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

9 Comments

Something is wrong. Doesn't list[y] = list[x] - list[x]; just equate to list[y] = 0;?
The xor trick also fails when x=y -- it sets list[x] to zero, when you might expect it to keep list[x] the original value.
Technically you make a temp value you just dont move it outside the relevant area of the array.
Neither simpler, neither more efficient, neither generic.
This might be acceptable in C, but it's not good Javascript. It can only be treated as a swap if certain properties can be guaranteed about the elements, e.g. they are both ints. Even with the arithmetic version, there's a good chance of precision loss with floats. And yes, it's also horribly unclear. At least the initial version of this answer admitted it was nasty.
|
18

To swap two consecutive elements of an array:

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

Comments

15

Use destructuring assignment:

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

which can also be extended to

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

1 Comment

That is already covered in this answer.
14

For two or more elements (fixed number)

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

No temporary variable required!

I was thinking about simply calling list.reverse().
But then I realised it would work as swap only when list.length = x + y + 1.

For variable number of elements

I have looked into various modern Javascript constructions to this effect, including Map and map, but sadly none has resulted in a code that was more compact or faster than this old-fashioned, loop-based construction:

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>

Comments

13

Digest from Single line JavaScript integer variable swap:

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

3 Comments

If you wrap this in a swap(a, b) function you don't need to worry about readability.
Works only for integers
This probably optimises poorly. A compiler might detect it as a "swap idiom", but can't be sure of the effects unless it can be sure that both types are ints, and also that they don't alias.
7

You can swap any number of objects or literals, even of different types, using a simple identity function like this:

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

For your problem:

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

This works in JavaScript because it accepts additional arguments even if they are not declared or used. The assignments a=b etc, happen after a is passed into the function.

1 Comment

Hackish...but you could do one better, if you are only using the function once: list[y] = (function(x){return x})(list[x],list[x]=list[y]);. Or, if you're interested in ES6 (next version of JS), it's insanely easy: [list[x], list[y]] = [list[y], list[x]. I'm so glad they are adding some more functional and class-based aspects into the next version of JavaScript.
7

There is one interesting way of swapping:

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

(ES6 way)

1 Comment

for an array, it's more var a= [7,8,9,10], i=2, j=3;[a[i],a[j]] = [a[j],a[i]];
6

Here's a one-liner that doesn't mutate list:

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

(Uses language features not available in 2009 when the question was posted!)

Comments

4

Flow

Not an in place solution:

let swap = (arr, i, j) => arr.map((e, k) => k-i ? (k-j ? e : arr[i]) : arr[j]);

let swap = (arr, i, j) => arr.map((e, k) => k-i ? (k-j ? e : arr[i]) : arr[j]);

// Test index: 3<->5 (= 'f'<->'d')
let a = ["a", "b", "c", "d", "e", "f", "g"];
let b = swap(a, 3, 5);

console.log(a, "\n", b);
console.log('Example Flow:', swap(a, 3, 5).reverse().join('-'));

And an in place solution:

let swap = (arr, i, j) => {let t = arr[i]; arr[i] = arr[j]; arr[j] = t; return arr}

// Test index: 3<->5 (= 'f'<->'d')
let a = ["a", "b", "c", "d", "e", "f", "g"];

console.log(swap(a, 3, 5))
console.log('Example Flow:', swap(a, 3, 5).reverse().join('-'));

In these solutions, we use the "flow pattern" which means that the swap function returns an array as the result. This allows it to easily continue processing using dot . (like reverse and join in snippets).

Comments

3
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];

Comments

3

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

1 Comment

While this code snippet may solve the question, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion.
2

Here's a compact version. It swaps the value at i1 with i2 in arr:

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

1 Comment

That is less efficient then the temporary variable method. You're effectively returning a modified array that was sliced three times and concatenated together with two objects between the three sliced arrays. You've effectively required more than twice the memory than necessary to get the value to simply assign to the array (none of that was done in place).
2

A TypeScript solution that clones the array instead of mutating an existing one:

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

Comments

2

Using JavaScript ES6 features:

// Example 1: swapping array index

let arr = ["one", "two"];
[arr[0], arr[1]] = [arr[1], arr[0]];

// Output: arr = ["two", "one"]
console.log(arr);

// Example 2: swapping two variables value

let a = 10;
let b = 20;

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

// Output: a = 20, b = 10;

console.log(a, b);

Comments

1

Here is a variation that first checks if the index exists in the 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;
}

It currently will just return this if the index does not exist, but you could easily modify behavior on fail

Comments

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

Usage:

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

3 Comments

No need to be rude. Also, extending the Array prototype was not part of what was asked for - it may confuse more than it does good.
You are expressing it as "the correct way". It may give the wrong impression. Instead, I would suggest mentioning what you are doing (extending the prototype), and how it is useful, exactly as you just described to me.
Well then maybe consider deleting your answer, or following the advice of people describing why they gave you the vote they did.
1

If you are not allowed to use in-place swap for some reason, here is a solution with map:

function swapElements(array, source, dest) {
  return source === dest
? array : array.map((item, index) => index === source
  ? array[dest] : index === dest 
  ? array[source] : item);
}

const arr = ['a', 'b', 'c'];
const s1 = swapElements(arr, 0, 1);
console.log(s1[0] === 'b');
console.log(s1[1] === 'a');

const s2 = swapElements(arr, 2, 0);
console.log(s2[0] === 'c');
console.log(s2[2] === 'a');

Here is typescript code for quick copy-pasting:

function swapElements(array: Array<any>, source: number, dest: number) {
  return source === dest
    ? array : array.map((item, index) => index === source
      ? array[dest] : index === dest 
      ? array[source] : item);
}

Comments

1

ES2023 Array Method with():

The with() method of Array instances is the copying version of using the bracket notation to change the value of a given index. It returns a new array with the element at the given index replaced with the given value.

const list = [1, 2, 3], x= 0, y= 1;
console.log(list.with(x,list[y]).with(y,list[x])); // [2, 1, 3]

PS: with() method is supported nearly by all browsers and on Node.js version 20+.
see browser compatibility

Comments

1

If you don't want to use a temporary variable in ES5, this is one way to swap array elements.

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 ]

4 Comments

This way, instead of creating a temp variable you are creating 2 new arrays as a.splice returns an array with the removed elements. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Is there any way that we can do it better? @Cristy
Accepted answer is straight forward one. This will be handy when you have a limitation on number of variables declaration (mostly interview purpose :) ). But not memory efficient as you mentioned. @Cristy
I personally think it's a bad practice and should not be recommended to beginners. It's also very hard to read.
0

For the sake of brevity, here's the ugly one-liner version that's only slightly less ugly than all that concat and slicing above. The accepted answer is truly the way to go and way more readable.

Given:

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

if you want to swap the values of two indices (a and b); then this would do it:

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

For example, if you want to swap the 3 and 5, you could do it this way:

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

or

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

Both yield the same result:

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

#splicehatersarepunks:)

Comments

0

Now you can swap the array element into a different random position.

function swapRandomValues(arr, numValues) {
  if (numValues > arr.length / 2) {
    console.log("Cannot swap more than half of the array.");
    return;
  }
  for (let i = 0; i < numValues; i++) {
    let randomIndex1 = Math.floor(Math.random() * arr.length);
    let randomIndex2 = Math.floor(Math.random() * arr.length);
    [arr[randomIndex1],arr[randomIndex2]] = [arr[randomIndex2],arr[randomIndex2]]
  }
  console.log(arr);
}

let arr = [1,2,3,4,5,6,7,8,9,10,11,12];
swapRandomValues(arr, 6);

Comments

0

Swap the first and last element in an array without a temporary variable or the ES6 swap method [a, b] = [b, a]:

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.