Javascript swap array elements

Viewed 459385

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;
33 Answers

You only need one temporary variable.

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

Edit hijacking top answer 10 years later with a lot of ES6 adoption under our belts:

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.

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.

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.

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

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

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.

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

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

Flow

not inplace 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 inplace 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 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)

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 ]

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

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

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

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()]

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

in place swap

// array methods
function swapInArray(arr, i1, i2){
    let t = arr[i1];
    arr[i1] = arr[i2];
    arr[i2] = t;
}

function moveBefore(arr, el){
    let ind = arr.indexOf(el);
    if(ind !== -1 && ind !== 0){
        swapInArray(arr, ind, ind - 1);
    }
}

function moveAfter(arr, el){
    let ind = arr.indexOf(el);
    if(ind !== -1 && ind !== arr.length - 1){
        swapInArray(arr, ind + 1, ind);
    }
}

// dom methods
function swapInDom(parentNode, i1, i2){
    parentNode.insertBefore(parentNode.children[i1], parentNode.children[i2]);
}

function getDomIndex(el){
    for (let ii = 0; ii < el.parentNode.children.length; ii++){
        if(el.parentNode.children[ii] === el){
            return ii;
        }
    }
}

function moveForward(el){
    let ind = getDomIndex(el);
    if(ind !== -1 && ind !== 0){
        swapInDom(el.parentNode, ind, ind - 1);
    }
}

function moveBackward(el){
    let ind = getDomIndex(el);
    if(ind !== -1 && ind !== el.parentNode.children.length - 1){
        swapInDom(el.parentNode, ind + 1, ind);
    }
}

try this function...

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

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