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
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:
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_
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.
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('-') );
_x000D_
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('-') );
_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:
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_
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...
$(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_
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");
[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
.
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]);
_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: </td> <td><code></code></td></tr>
</table>
_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:)
var arr = [1, 2];_x000D_
arr.splice(0, 2, arr[1], arr[0]);_x000D_
console.log(arr); //[2, 1]
_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];
Source: Stackoverflow.com