[javascript] Javascript swap array elements

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

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

This question is related to javascript arrays

The answer is


According to some random person on Metafilter, "Recent versions of Javascript 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.


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

_x000D_
_x000D_
function swap(arr, from, to) {_x000D_
  arr.splice(from, 1, arr.splice(to, 1, arr[from])[0]);_x000D_
}_x000D_
_x000D_
var letters = ["a", "b", "c", "d", "e", "f"];_x000D_
_x000D_
swap(letters, 1, 4);_x000D_
_x000D_
console.log(letters); // ["a", "e", "c", "d", "b", "f"]
_x000D_
_x000D_
_x000D_

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.


Flow

not inplace solution

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

_x000D_
_x000D_
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('-') );
_x000D_
_x000D_
_x000D_

and inplace solution

_x000D_
_x000D_
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('-') );
_x000D_
_x000D_
_x000D_

In this solutions we use "flow pattern" which means that swap function returns array as result - this allow to easily continue processing using dot . (like reverse and join in snippets)


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.


Here's a compact version swaps 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))

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

Typescript solution that clones the array instead of mutating 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;
}

Just for the fun of it, another way without using any extra variable would be:

_x000D_
_x000D_
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];_x000D_
_x000D_
// swap index 0 and 2_x000D_
arr[arr.length] = arr[0];   // copy idx1 to the end of the array_x000D_
arr[0] = arr[2];            // copy idx2 to idx1_x000D_
arr[2] = arr[arr.length-1]; // copy idx1 to idx2_x000D_
arr.length--;               // remove idx1 (was added to the end of the array)_x000D_
_x000D_
_x000D_
console.log( arr ); // -> [3, 2, 1, 4, 5, 6, 7, 8, 9]
_x000D_
_x000D_
_x000D_


Using ES6 it's possible to do it like this...

Imagine you have these 2 arrays...

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

and you want to swap the first values:

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

and value:

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

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.


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


If need swap first and last elements only:

array.unshift( array.pop() );

try this function...

_x000D_
_x000D_
$(document).ready(function () {_x000D_
        var pair = [];_x000D_
        var destinationarray = ['AAA','BBB','CCC'];_x000D_
_x000D_
        var cityItems = getCityList(destinationarray);_x000D_
        for (var i = 0; i < cityItems.length; i++) {_x000D_
            pair = [];_x000D_
            var ending_point = "";_x000D_
            for (var j = 0; j < cityItems[i].length; j++) {_x000D_
                pair.push(cityItems[i][j]);_x000D_
            }_x000D_
            alert(pair);_x000D_
            console.log(pair)_x000D_
        }_x000D_
_x000D_
    });_x000D_
    function getCityList(inputArray) {_x000D_
        var Util = function () {_x000D_
        };_x000D_
_x000D_
        Util.getPermuts = function (array, start, output) {_x000D_
            if (start >= array.length) {_x000D_
                var arr = array.slice(0);_x000D_
                output.push(arr);_x000D_
            } else {_x000D_
                var i;_x000D_
_x000D_
                for (i = start; i < array.length; ++i) {_x000D_
                    Util.swap(array, start, i);_x000D_
                    Util.getPermuts(array, start + 1, output);_x000D_
                    Util.swap(array, start, i);_x000D_
                }_x000D_
            }_x000D_
        }_x000D_
_x000D_
        Util.getAllPossiblePermuts = function (array, output) {_x000D_
            Util.getPermuts(array, 0, output);_x000D_
        }_x000D_
_x000D_
        Util.swap = function (array, from, to) {_x000D_
            var tmp = array[from];_x000D_
            array[from] = array[to];_x000D_
            array[to] = tmp;_x000D_
        }_x000D_
        var output = [];_x000D_
        Util.getAllPossiblePermuts(inputArray, output);_x000D_
        return output;_x000D_
    }
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
_x000D_
_x000D_
_x000D_


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!)


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

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

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

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

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


This didn't exist when the question was asked, but ES2015 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

function moveElement(array, sourceIndex, destinationIndex) {
    return array.map(a => a.id === sourceIndex ? array.find(a => a.id === destinationIndex): a.id === destinationIndex ? array.find(a => a.id === sourceIndex) : a )
}
let arr = [
{id: "1",title: "abc1"},
{id: "2",title: "abc2"},
{id: "3",title: "abc3"},
{id: "4",title: "abc4"}];

moveElement(arr, "2","4");

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:

_x000D_
_x000D_
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]);
_x000D_
<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>
_x000D_
_x000D_
_x000D_


what about 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]

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]

If you don't want to use temp 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 ]

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:)


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


There is one interesting way of swapping:

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

(ES6 way)


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

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

To swap two consecutive elements of array

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

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"

Edit:

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.


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