【发布时间】:2010-10-26 17:13:09
【问题描述】:
有没有更简单的方法来交换数组中的两个元素?
var a = list[x], b = list[y];
list[y] = a;
list[x] = b;
【问题讨论】:
标签: javascript arrays
有没有更简单的方法来交换数组中的两个元素?
var a = list[x], b = list[y];
list[y] = a;
list[x] = b;
【问题讨论】:
标签: javascript arrays
您只需要一个临时变量。
var b = list[y];
list[y] = list[x];
list[x] = b;
编辑在 10 年后劫持了最佳答案,我们大量采用了 ES6:
给定数组arr = [1,2,3,4],您现在可以像这样在一行中交换值:
[arr[0], arr[1]] = [arr[1], arr[0]];
这将产生数组[2,1,3,4]。这是destructuring assignment。
【讨论】:
a = [b, b = a][0]; 虽然我仍然发现自己在使用临时变量方法,因为它是跨语言(例如 C/C++),也是我通常想到的第一种方法。
[ list[y], list[x] ] = [ list[x], list[y] ];
[arr[1], arr[0]] 会改变原始数组吗?这对我来说似乎难以置信。
如果你想要一个表达式,使用原生 javascript, 请记住拼接操作的返回值 包含被移除的元素。
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"
编辑:
[0] 在表达式末尾是必需的,因为Array.splice() 返回一个数组,在这种情况下,我们需要返回数组中的单个元素。
【讨论】:
[A[x]] = A.splice(y, 1, A[x]) !
这似乎没问题....
var b = list[y];
list[y] = list[x];
list[x] = b;
如何使用
var b = list[y];
表示 b 变量将在范围的其余部分出现。这可能会导致内存泄漏。不太可能,但还是最好避免。
把它放到 Array.prototype.swap 中可能是个好主意
Array.prototype.swap = function (x,y) {
var b = this[x];
this[x] = this[y];
this[y] = b;
return this;
}
可以这样称呼:
list.swap( x, y )
这是避免内存泄漏和DRY的干净方法。
【讨论】:
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; };
根据some random person on Metafilter, “最新版本的 Javascript 允许您更巧妙地进行交换(除其他外):”
[ list[x], list[y] ] = [ list[y], list[x] ];
我的快速测试表明 Pythonic code 在 JavaScript 版本中运行良好 目前在“Google Apps 脚本”(“.gs”)中使用。 唉,进一步的测试表明此代码给出了“未捕获的 ReferenceError:分配中的左侧无效”。在 使用任何版本的 JavaScript (".js") 谷歌浏览器版本 24.0.1312.57 m.
【讨论】:
嗯,您不需要缓冲 两个 值 - 只需要一个:
var tmp = list[x];
list[x] = list[y];
list[y] = tmp;
【讨论】:
您可以通过以下方式交换数组中的元素:
list[x] = [list[y],list[y]=list[x]][0]
请看下面的例子:
list = [1,2,3,4,5]
list[1] = [list[3],list[3]=list[1]][0]
//list is now [1,4,3,2,5]
注意:它对常规变量的工作方式相同
var a=1,b=5;
a = [b,b=a][0]
【讨论】:
[list[x], list[y]] = [list[y], list[x]];。
this[0] > this[1] && (this[0] = [this[1],this[1]=this[0]][0]);
提问的时候这个是不存在的,但是ES2015引入了数组解构,可以这样写:
let a = 1, b = 2;
// a: 1, b: 2
[a, b] = [b, a];
// a: 2, b: 1
【讨论】:
[list[x], list[y]] = [list[y], list[x]];
交换数组的两个连续元素
array.splice(IndexToSwap,2,array[IndexToSwap+1],array[IndexToSwap]);
【讨论】:
对于数值,您可以使用按位异或来避免临时变量
list[x] = list[x] ^ list[y];
list[y] = list[y] ^ list[x];
list[x] = list[x] ^ list[y];
或算术和(注意这仅在 x + y 小于数据类型的最大值时才有效)
list[x] = list[x] + list[y];
list[y] = list[x] - list[y];
list[x] = list[x] - list[y];
【讨论】:
list[y] = list[x] - list[x]; 不等于 list[y] = 0; 吗?
考虑这样的解决方案,不需要定义第三个变量:
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"]
注意:您可能需要添加额外的检查,例如数组长度。这个解决方案是可变的所以swap函数不需要返回一个新的数组,它只是对传入的数组进行突变。
【讨论】:
arr.splice(from, 1, arr.splice(to, 1, ...arr[from]))
var arr = [1, 2, 3, 4]
[arr[index1], arr[index2]] = [arr[index2], arr[index1]]
也可以扩展为
[src order elements] => [dest order elements]
【讨论】:
[list[y], list[x]] = [list[x], list[y]];
不需要临时变量!
我在考虑直接打电话给list.reverse()。
但后来我意识到它只有在list.length = x + y + 1 时才能用作交换。
为此,我研究了各种现代 Javascript 结构,包括 Map 和 map,但遗憾的是,没有一个代码比这种老式的、基于循环的结构更紧凑或更快:
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: </td> <td><code></code></td></tr>
</table>
【讨论】:
摘自http://www.greywyvern.com/?post=265
var a = 5, b = 9;
b = (a += b -= a) - b;
alert([a, b]); // alerts "9, 5"
【讨论】:
swap(a, b) 函数中,你就不需要担心可读性了。
您可以使用如下简单的标识函数交换任意数量的对象或文字,甚至是不同类型的对象或文字:
var swap = function (x){return x};
b = swap(a, a=b);
c = swap(a, a=b, b=c);
针对您的问题:
var swap = function (x){return x};
list[y] = swap(list[x], list[x]=list[y]);
这在 JavaScript 中有效,因为它接受额外的参数,即使它们没有被声明或使用。 a=b 等赋值发生在 a 被传递到函数之后。
【讨论】:
list[y] = (function(x){return x})(list[x],list[x]=list[y]);。或者,如果你对 ES6(JS 的下一个版本)感兴趣,这非常简单:[list[x], list[y]] = [list[y], list[x]。我很高兴他们在下一版本的 JavaScript 中添加了更多功能和基于类的方面。
有一种有趣的交换方式:
var a = 1;
var b = 2;
[a,b] = [b,a];
(ES6方式)
【讨论】:
var a= [7,8,9,10], i=2, j=3;[a[i],a[j]] = [a[j],a[i]];
这是一个不会变异的单行代码list:
let newList = Object.assign([], list, {[x]: list[y], [y]: list[x]})
(使用问题发布时 2009 年不可用的语言功能!)
【讨论】:
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];
【讨论】:
这是一个精简版 用 arr 中的 i2 交换 i1 的值
arr.slice(0,i1).concat(arr[i2],arr.slice(i1+1,i2),arr[i1],arr.slice(i2+1))
【讨论】:
var arr = [1, 2];
arr.splice(0, 2, arr[1], arr[0]);
console.log(arr); //[2, 1]
【讨论】:
没有就地解决方案
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('-') );
并就地解决方案
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('-') );
在这个解决方案中,我们使用 "flow pattern",这意味着 swap 函数返回数组作为结果 - 这允许使用点 . 轻松继续处理(如 sn-ps 中的 reverse 和 join)
【讨论】:
这是一个首先检查索引是否存在于数组中的变体:
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;
}
如果索引不存在,它目前只会返回this,但您可以轻松修改失败时的行为
【讨论】:
如果你不想在 ES5 中使用 temp 变量,这是交换数组元素的一种方法。
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 ]
【讨论】:
a.splice 返回一个包含已删除元素的数组。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
克隆数组而不是改变现有数组的 Typescript 解决方案
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;
}
【讨论】:
为简洁起见,这里是丑陋的单线版本,它只比上面所有的 concat 和 slicing 稍微丑一点。接受的答案确实是要走的路,而且更具可读性。
给定:
var foo = [ 0, 1, 2, 3, 4, 5, 6 ];
如果你想交换两个索引(a 和 b)的值;然后就可以了:
foo.splice( a, 1, foo.splice(b,1,foo[a])[0] );
例如,如果你想交换 3 和 5,你可以这样做:
foo.splice( 3, 1, foo.splice(5,1,foo[3])[0] );
或
foo.splice( 5, 1, foo.splice(3,1,foo[5])[0] );
两者产生相同的结果:
console.log( foo );
// => [ 0, 1, 2, 5, 4, 3, 6 ]
#splicehatersarepunks:)
【讨论】:
在没有临时变量或 ES6 交换方法 [a, b] = [b, a] 的情况下交换数组中的第一个和最后一个元素
[a.pop(), ...a.slice(1), a.shift()]
【讨论】:
Array.prototype.swap = function(a, b) {
var temp = this[a];
this[a] = this[b];
this[b] = temp;
};
用法:
var myArray = [0,1,2,3,4...];
myArray.swap(4,1);
【讨论】:
Array 原型并不是我们所要求的一部分——它可能会造成混淆而不是好处。
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");
【讨论】:
就地交换
// 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);
}
}
【讨论】:
如果由于某种原因不允许使用就地交换,这里有一个使用 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');
这是用于快速复制粘贴的打字稿代码:
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);
}
【讨论】:
为了好玩,另一种不使用任何额外变量的方法是:
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]
【讨论】: