【问题标题】:Javascript swap array elementsJavascript交换数组元素
【发布时间】:2010-10-26 17:13:09
【问题描述】:

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

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

【问题讨论】:

    标签: javascript arrays


    【解决方案1】:

    您只需要一个临时变量。

    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

    【讨论】:

    • 即使不使用 ECMAScript 6 解构赋值,实际上也可以实现同时交换,而不会使用临时变量污染当前范围:@Jan 指出的a = [b, b = a][0]; 虽然我仍然发现自己在使用临时变量方法,因为它是跨语言(例如 C/C++),也是我通常想到的第一种方法。
    • 您可以使用 es6 就地交换(变异),如下所示:[ list[y], list[x] ] = [ list[x], list[y] ];
    • @YerkoPalma - 表达式返回 [2,1],但原始数组将变为 [2,1,3,4]
    • 在这种情况下,es6 表达式可能效率低下,因为它正在生成一个新的且不必要的数组分配。
    • 有人可以向我解释为什么[arr[1], arr[0]] 会改变原始数组吗?这对我来说似乎难以置信。
    【解决方案2】:

    如果你想要一个表达式,使用原生 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() 返回一个数组,在这种情况下,我们需要返回数组中的单个元素。

    【讨论】:

    • 拼接返回一个数组。因此,在您的示例中,在交换操作之后,您的数组实际上看起来像: [[2], 1, 3, 4, 5, 6, 7, 8, 9]
    • 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]; } });
    • 确认,缺少[0]。
    • 很好很短,但正如@aelgoa 所说,几乎是慢然后简单的交换
    • 少 1 个字符 [A[x]] = A.splice(y, 1, A[x]) !
    【解决方案3】:

    这似乎没问题....

    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; } });
    • 这很好。也许一些边界检查? 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; };
    • @DavidR。边界检查是多余的和不必要的。如果需要,调用者拥有执行此类检查所需的一切,但在大多数情况下,您已经知道 x 和 y 在界限内,因为您处于某种循环中。
    • 难道你不能通过将它包装在一个函数中来避免“潜在的内存泄漏”吗?
    • 为了避免潜在的“扁平化”事故,我不会触及任何内置类型的原型链。
    【解决方案4】:

    根据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.

    【讨论】:

    • 这是 ES6 提案的一部分:它还没有正式化,因此不应该绝对假设它在任何地方都可以工作(如果可以的话,那就太棒了......)。
    • 在当前firefox最新版本(39.0.3)下工作。
    • 它适用于 Chrome 版本 54.0.2840.71 及更早版本。此外,如果您使用 ES6 转译器,例如 babel,这应该是您的必备代码。
    • 喜欢这个解决方案。清洁,如预期。太糟糕了,这个问题是 9 年前提出的......
    • 在 es6 中已经标准化,这个特性称为解构。
    【解决方案5】:

    嗯,您不需要缓冲 两个 值 - 只需要一个:

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

    【讨论】:

    • 你的“tmp”听起来比“b”更合理
    • @ofir_aghai 是的,你是对的:10 多年前,另一个答案发布在此之前 22 秒(12:14:16Z 与 12:14:38Z )...
    • 在平常的日子里,我一直坚持下去。但仅仅因为秒问题和对你 10 年的尊重在这里恢复;-)
    • 抱歉,它不允许我更改投票。“除非编辑此答案,否则您的投票现在已锁定”
    【解决方案6】:

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

    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]
    

    【讨论】:

    • 这与在 ES6(JavaScript 的下一个版本)中执行此操作的标准正确方法惊人地相似:[list[x], list[y]] = [list[y], list[x]];
    • 这与 ES6 数组解构交换无关。这只是对 JS 工作流的巧妙运用。如果您经常使用内联编码,这是一个漂亮的交换模式,例如this[0] > this[1] && (this[0] = [this[1],this[1]=this[0]][0]);
    【解决方案7】:

    提问的时候这个是不存在的,但是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]];
    【解决方案8】:

    交换数组的两个连续元素

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

    【讨论】:

      【解决方案9】:

      对于数值,您可以使用按位异或来避免临时变量

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

      【讨论】:

      • 是不是和维达一样? +1
      • 出了点问题。 list[y] = list[x] - list[x]; 不等于 list[y] = 0; 吗?
      • xor 技巧在 x=y 时也会失败——它将 list[x] 设置为零,而您可能希望它保持 list[x] 的原始值。
      • 从技术上讲,您可以创建一个临时值,而无需将其移到数组的相关区域之外。
      • 既不简单,也不高效,也不通用。
      【解决方案10】:

      考虑这样的解决方案,不需要定义第三个变量:

      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]))
      • 这就是我要找的,谢谢
      【解决方案11】:

      Destructuring_assignment

      var arr = [1, 2, 3, 4]
      [arr[index1], arr[index2]] = [arr[index2], arr[index1]]
      

      也可以扩展为

      [src order elements] => [dest order elements]
      

      【讨论】:

        【解决方案12】:

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

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

        【讨论】:

          【解决方案13】:

          摘自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) 函数中,你就不需要担心可读性了。
          • 仅适用于整数
          • 这可能优化得很差。编译器可能会将其检测为“交换习语”,但无法确定效果,除非它可以确定两种类型都是整数,而且它们不是 alias
          【解决方案14】:

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

          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 中添加了更多功能和基于类的方面。
          【解决方案15】:

          有一种有趣的交换方式:

          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]];
          【解决方案16】:

          这是一个不会变异的单行代码list

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

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

          【讨论】:

            【解决方案17】:
            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];
            

            【讨论】:

              【解决方案18】:

              这是一个精简版 用 arr 中的 i2 交换 i1 的值

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

              【讨论】:

              • 这比临时变量方法效率低。您实际上返回了一个修改后的数组,该数组被切片了三次,并与三个切片数组之间的两个对象连接在一起。您实际上需要两倍以上的内存来获取简单分配给数组的值(这些都没有完成)。
              【解决方案19】:

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

              【讨论】:

              • 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
              【解决方案20】:

              流程

              没有就地解决方案

              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 中的 reversejoin

              【讨论】:

                【解决方案21】:

                这是一个首先检查索引是否存在于数组中的变体:

                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,但您可以轻松修改失败时的行为

                【讨论】:

                  【解决方案22】:

                  如果你不想在 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 个新数组,因为 a.splice 返回一个包含已删除元素的数组。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
                  • 有什么方法可以做得更好吗? @克里斯蒂
                  • 接受的答案是直截了当的。当您对变量声明的数量有限制(主要是面试目的:))时,这将很方便。但不是你提到的内存效率。 @克里斯蒂
                  • 我个人认为这是一种不好的做法,不应该推荐给初学者。它也很难阅读。
                  【解决方案23】:

                  克隆数组而不是改变现有数组的 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;
                  }
                  

                  【讨论】:

                    【解决方案24】:

                    为简洁起见,这里是丑陋的单线版本,它只比上面所有的 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:)

                    【讨论】:

                      【解决方案25】:

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

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

                      【讨论】:

                        【解决方案26】:
                        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 原型并不是我们所要求的一部分——它可能会造成混淆而不是好处。
                        • 如何表达一些答案很疯狂,扩展数组原型并添加一个返回,这将使其能够链接......
                        • 您将其表达为“正确的方式”。它可能会给人错误的印象。相反,我建议您提及您正在做什么(扩展原型),以及它的用途,正如您刚刚向我描述的那样。
                        • 明白了,抱歉我的平衡有时不成对^_^
                        • 您是唯一一个描述答案上下文问题的人......首先,负分应该保留给非工作答案。其次,这是一个很好的答案,优雅的用法不会导致冲突。判断代码而不是交付。同样在我的回答中,如果您将其剥离并排除原型扩展,它将与投票最多的答案完全相同,因此这是 -6 的事实表明投票否决的人缺乏想法。并且在最佳答案前几个月发布......所以这听起来像是流行而不是代码竞赛。
                        【解决方案27】:
                        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");
                        

                        【讨论】:

                        • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更高,更有可能吸引投票。
                        【解决方案28】:

                        就地交换

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

                        【讨论】:

                          【解决方案29】:

                          如果由于某种原因不允许使用就地交换,这里有一个使用 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);
                          }
                          

                          【讨论】:

                            【解决方案30】:

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

                            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]

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2021-08-07
                              • 2012-09-21
                              • 1970-01-01
                              • 2015-07-05
                              • 2021-06-01
                              相关资源
                              最近更新 更多