JavaScript交换数组元素


228

有没有更简单的方法来交换数组中的两个元素?

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

Answers:


411

您只需要一个临时变量。

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

十年后编辑劫持性最高答案,并采用了许多ES6:

给定array arr = [1,2,3,4],您现在可以在一行中交换值,如下所示:

[arr[0], arr[1]] = [arr[1], arr[0]];

这将产生数组[2,1,3,4]。这是破坏性的任务


2
即使不使用ECMAScript 6进行结构分解分配,实际上也可以实现同时交换而不会用临时变量污染当前范围:a = [b, b = a][0];@Jan指出,尽管我仍然发现自己使用了临时变量方法,因为它是跨语言的(例如C / C ++) ),这是我通常会想到的第一种方法。
Ultimater

3
您可以与es6交换就位(变异),如下所示:[ list[y], list[x] ] = [ list[x], list[y] ];
protoEvangelion

[arr[0], arr[1]] = [arr[1], arr[0]]仅在[2, 1]没有其余阵列的情况下生产
Yerko Palma

8
@YerkoPalma-表达式返回[2,1],但是原始数组将被突变为[2,1,3,4]
danbars

111

如果要使用本地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()的阵列的回报,并且在这种情况下,我们所需要的返回数组中的单个元件。


3
splice返回一个数组。因此,在您的示例中,交换操作之后,您的数组实际上看起来像:[[2],
1、3、4、5、6、7、8、9

1
A [x] = A.splice(y,1,A [x])[0]; ?在mootools中Array.implement({swap:function(x,y){this [y] = this.splice(x,1,this [y])[0];}});


不错,很短,但是正如@aelgoa所说,几乎是缓慢然后简单的交换
ofir_aghai

75

好像还可以

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.implement({swap:function(x,y){x = this [x]; this [x] = this [y]; this [y] = x; return this;}});

1
很好 也许有些界限检查?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; };
David R.

@DavidR。边界检查是多余且不必要的。调用者拥有执行此检查(如果需要的话)所需的一切,尽管在大多数情况下,您已经知道x和y处于边界,因为您处于某种循环中。
Neil 2015年

6
您是否仅通过将其包装在函数中来避免“潜在的内存泄漏”?
Carcigenicate '16

3
为了避免潜在的“变平”事故,我不会碰任何内置类型的原型链。
AaronDancer 18'Apr

54

Metafilter上的一个随机人士说,“ Java的最新版本使您可以更巧妙地进行交换(除其他事项外):”

[ list[x], list[y] ] = [ list[y], list[x] ];

我的快速测试表明,这种Pythonic代码在“ Google Apps脚本”(“ .gs”)当前使用的JavaScript版本中效果很好。further,进一步的测试表明此代码给出了“ Uncaught ReferenceError:分配中的无效左侧”。Google Chrome版本24.0.1312.57 m使用任何版本的JavaScript(“ .js”)。


2
这是ES6提案的一部分:它尚未正式化,因此不应绝对假定它可在任何地方都可以使用(如果这样做的话会很棒……)。
伊西亚·梅多斯

2
它可以在最新的firefox最新版本(39.0.3)中工作。
杰米

2
它可以在Chrome版本54.0.2840.71和更早版本中使用。另外,如果您使用诸如babel之类的ES6编译器,这应该是您的入门代码。
变形虫

3
喜欢这个解决方案。按预期清洁。太糟糕了,这个问题是9年前提出的...
DavidsKanal

2
它已在es6中标准化,此功能称为解构。
AL-zami

29

好吧,您不需要缓存两个值-仅一个:

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

13
您的'tmp'听起来比'b'更加合理
mtasic85

@ofir_aghai是的,您是对的:10年前,在此答案之前22秒发布了另一个答案(12:14:16Z与12:14:38Z)...
Marc Gravell

在平常的日子里,我坚持下去。只是因为秒数问题和对您10年的尊重在这里恢复了;-)
ofir_aghai

抱歉,它不允许我更改投票。.“您的投票现已锁定,除非编辑了此答案”
ofir_aghai

22

您可以通过以下方式交换数组中的元素:

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]

6
这非常类似于ES6(JavaScript的下一个版本)中执行此操作的标准正确方法:[list[x], list[y]] = [list[y], list[x]];
Isiah Meadows

1
这与我们通过解构进行ES6阵列交换无关。这只是对JS工作流的巧妙使用。如果您频繁使用内联编码,则可以使用漂亮的交换模式,例如this[0] > this[1] && (this[0] = [this[1],this[1]=this[0]][0]);
Redu

18

使用数字值时,可以通过按位异或来避免使用临时变量

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

2
那个达斯和维达一样吗?+1
krosenvold

7
出了点问题。不list[y] = list[x] - list[x];只是等同于list[y] = 0;
ErikE 2012年

3
当x = y时,xor技巧也会失败-当您可能希望list [x]保持list [x]原始值时,它将x [y]设置为零。
大卫·卡里

1
从技术上讲,您只需将温度值移到数组的相关区域之外即可。
马克·史密特

1
既不简单,也不高效,也不通用。
LoganMzz

17

提出问题时不存在此问题,但是ES2015引入了数组解构,使您可以按以下方式编写它:

let a = 1, b = 2;
// a: 1, b: 2
[a, b] = [b, a];
// a: 2, b: 1

14
像这样在阵列内交换:[list[x], list[y]] = [list[y], list[x]];
Stromata




9

考虑这种解决方案,而无需定义第三个变量:

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]))
Orkun Tuzel

7

您可以使用以下简单的标识函数交换任意数量的对象或文字,甚至不同类型的文字:

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传递到函数后发生。


hackish的...但你可以做一个更好的,如果你只使用一次的函数:list[y] = (function(x){return x})(list[x],list[x]=list[y]);。或者,如果你有兴趣ES6(JS的下一个版本),这是出奇的简单:[list[x], list[y]] = [list[y], list[x]。我很高兴他们在下一个JavaScript版本中添加了更多基于功能和基于类的方面。
伊西亚·梅多斯

6

对于两个或多个元素(固定数量)

[list[y], list[x]] = [list[x], list[y]];

无需临时变量!

我在想简单地打电话list.reverse()
但后来我意识到,仅当时,它才可以作为交换list.length = x + y + 1

对于可变数量的元素

为此,我研究了各种现代Javascript构造,包括Mapmap,但遗憾的是,没有一个代码比这种老式的基于循环的构造更紧凑或更快速:

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>


5

有一种有趣的交换方式:

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

(ES6方式)


5
对于阵列,则更多var a= [7,8,9,10], i=2, j=3;[a[i],a[j]] = [a[j],a[i]];
caub 2015年


3

这是一个不会变异的单线list

let newList = Object.assign([], list, {[x]: list[y], [y]: list[x]})

(使用发布问题时2009年不可用的语言功能!)


1

这是一个紧凑版本,将i1的值与arr中的i2交换

arr.slice(0,i1).concat(arr[i2],arr.slice(i1+1,i2),arr[i1],arr.slice(i2+1))

这比临时变量方法效率低。您实际上是在返回修改后的数组,该数组被切成三倍,并与三个切成的数组之间的两个对象串联在一起。实际上,您需要的内存多于获得简单分配给数组的值所需的内存(没有一个就位)。
Isiah Meadows

1

下面是一个变体,它首先检查数组中是否存在索引:

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如果索引不存在,它将仅返回,但是如果失败,您可以轻松修改行为


1

交换没有临时变量或ES6交换方法的数组中的第一个和最后一个元素[a,b] = [b,a]

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


1

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

0

只是为了好玩,不使用任何额外变量的另一种方法是:

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]


0

为了简洁起见,这是丑陋的单线版本,仅比上面所有合并和切片的丑陋程度小。公认的答案确实是一种使方法更具可读性的方法。

鉴于:

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


0

如果您不想在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 ]

这样,您将创建2个新数组,而不是创建temp变量,这a.splice将返回一个包含已删除元素的数组。developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…–
XCS

有什么办法可以做得更好?@Cristy
venkat7668

接受的答案是直接的。如果您对变量声明的数量有所限制(主要是访问目的:)),这将很方便。但是您提到的内存效率不高。@Cristy
venkat7668

我个人认为这是一种不好的做法,因此不建议初学者使用。这也很难读。
XCS

0

试试这个功能...

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



-1

使用ES6可以像这样做...

假设您有这两个数组 ...

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

并且您想交换第一个值:

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

和价值:

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

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

1
无需粗鲁。同样,扩展Array原型也不是要求的一部分,这可能会混淆其效果。
Mathias Lykkegaard Lorenzen

如何表达一些答案是疯狂的,扩展数组原型将是一个错误,并且添加返回值将使其具有链接能力……
user2472643 16-10-17

2
您将其表达为“正确的方式”。可能会给人留下错误的印象。相反,我建议提一下您在做什么(扩展原型)以及它的用处,就像您刚刚对我描述的那样。
Mathias Lykkegaard Lorenzen

1
不好意思,对不起,我的平衡有时不成对^ _ ^
user2472643 16-10-27

2
您是描述答案上下文问题的唯一人...首先,负分数应保留给无效答案。其次,这是一个很好的答案,且用法优雅,不会引起冲突。判断代码而不是交付。同样在我的答案中,如果您将其删除并排除了原型扩展,则它与投票最多的答案完全相同,因此,事实为-6表示投票否决的人缺乏思想。并在最佳答案的几个月前就发布了...所以这听起来像是一场流行,而不是一场代码竞赛。
user2472643

-3

如果需要仅交换第一个和最后一个元素:

array.unshift( array.pop() );

此代码有缺陷。它采用数组的最后一个元素,然后将其放在开头,这不是交换。此代码执行此操作: [1, 2, 3] => [3, 1, 2]代替[1, 2, 3] => [3, 2, 1]
大卫·阿奇博尔德
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.