ken
ken

Reputation: 5086

Swap array elements in JavaScript

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;

Upvotes: 354

Views: 541038

Answers (30)

Pavasiya Milan
Pavasiya Milan

Reputation: 1

var letters = ["a", "b", "c", "d", "e", "f"];

function swap (arr, from, to) {
    let temp = arr[from];
    arr.splice(from, 1, arr[to]);
    arr.splice(to, 1, temp);
}

swap(letters, 1, 4)
console.log(letters); // output [ 'a', 'e', 'c', 'd', 'b', 'f' ]

Upvotes: 0

Aniket Raj
Aniket Raj

Reputation: 2141

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

Upvotes: 2

Weilory
Weilory

Reputation: 3101

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

Upvotes: 0

Kamil Kiełczewski
Kamil Kiełczewski

Reputation: 92327

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

Upvotes: 4

Adam Pietrasiak
Adam Pietrasiak

Reputation: 13184

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

Upvotes: 1

gengns
gengns

Reputation: 1633

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

Upvotes: 0

venkat7668
venkat7668

Reputation: 2767

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 ]

Upvotes: 1

ROROROOROROR
ROROROOROROR

Reputation: 1109

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]

Upvotes: 15

dirkdig
dirkdig

Reputation: 499

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

Upvotes: 23

Alex Moonlight
Alex Moonlight

Reputation: 15

If there is a need to swap the first and last elements only:

array.unshift( array.pop() );

Upvotes: -3

user2044802
user2044802

Reputation: 57

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

Upvotes: 2

David Cary
David Cary

Reputation: 5490

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.

Upvotes: 89

Piyush Madan
Piyush Madan

Reputation: 181

To swap two consecutive elements of an array:

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

Upvotes: 17

R-way Orz
R-way Orz

Reputation: 163

Digest from Single line JavaScript integer variable swap:

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

Upvotes: 13

kennebec
kennebec

Reputation: 104760

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.

Upvotes: 133

Jakub Arnold
Jakub Arnold

Reputation: 87210

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

Upvotes: 18

tvanfosson
tvanfosson

Reputation: 532435

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.

Upvotes: 696

XMehdi01
XMehdi01

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

Upvotes: 1

Mirza Hayat
Mirza Hayat

Reputation: 402

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

Upvotes: 0

snnsnn
snnsnn

Reputation: 13600

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

Upvotes: 1

Pooja Sahani
Pooja Sahani

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

Upvotes: -1

JATIN KUMAR NAYAK
JATIN KUMAR NAYAK

Reputation: 39

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

Upvotes: 3

Alireza
Alireza

Reputation: 104650

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]

Upvotes: -2

Shevchenko Viktor
Shevchenko Viktor

Reputation: 5396

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.

Upvotes: 21

Pryme8
Pryme8

Reputation: 153

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

Upvotes: 1

Jasonovich
Jasonovich

Reputation: 659

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

Upvotes: 0

fmg
fmg

Reputation: 925

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

Upvotes: 6

Vivek
Vivek

Reputation: 4886

There is one interesting way of swapping:

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

(ES6 way)

Upvotes: 7

7vujy0f0hy
7vujy0f0hy

Reputation: 9109

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>

Upvotes: 14

vsync
vsync

Reputation: 130065

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

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

// swap index 0 and 2
arr[arr.length] = arr[0];   // copy idx1 to the end of the array
arr[0] = arr[2];            // copy idx2 to idx1
arr[2] = arr[arr.length-1]; // copy idx1 to idx2
arr.length--;               // remove idx1 (was added to the end of the array)


console.log( arr ); // -> [3, 2, 1, 4, 5, 6, 7, 8, 9]

Upvotes: -1

Related Questions