【问题标题】:Reverse array in Javascript without mutating original arrayJavascript中的反向数组而不改变原始数组
【发布时间】:2015-08-17 02:21:15
【问题描述】:

Array.prototype.reverse 反转原地数组的内容(带有突变)...

是否有类似的简单策略来反转数组而不改变原始数组的内容(不改变)?

【问题讨论】:

标签: javascript arrays


【解决方案1】:

您可以使用slice() 进行复制,然后使用reverse()

var newarray = array.slice().reverse();

var array = ['a', 'b', 'c', 'd', 'e'];
var newarray = array.slice().reverse();

console.log('a', array);
console.log('na', newarray);

【讨论】:

  • @Alex slice - If begin is omitted, slice begins from index 0. - 所以和array.slice(0)一样
  • 我认为@Alex 的意思是'在你的答案中解释'......无论如何......出色的解决方案。谢谢!
  • 我不建议使用这种方法,因为这是一种非常具有误导性的做法。当你使用 slice() 并且你实际上没有切片任何东西时,这非常令人困惑。如果您需要不可变的反向,只需创建新副本:const newArray = [...array].reverse()
  • 我们可以花一点时间来确定 JavaScript 需要进一步发展多少吗?这是我们最好的吗?来吧 JavaScript!长大一点。
  • @OlegMatei 切片整个数组仍在切片。如果您了解 Array#slice 的作用,就不会感到困惑。传播语法没有理由不那么令人困惑。
【解决方案2】:

在 ES6 中:

const newArray = [...array].reverse()

【讨论】:

  • 与公认答案的性能相比如何?它们是一样的吗?
  • 我一直在获得.slice 的速度明显更快。
  • @JamesCoyle 这可能取决于浏览器和操作系统,但slice 可能更快 b/c [...] 是一个通用的可迭代数组,因此不能做出尽可能多的假设。同样,slice 可能会更好地优化 b/c 它已经存在很长时间了。
  • 我的想法完全正确。
  • 查看stackoverflow.com/a/52929821/1480587,了解不同版本的数组复制基准。
【解决方案3】:

另一个 ES6 变体:

我们还可以使用.reduceRight() 创建一个反转数组,而无需实际反转它。

let A = ['a', 'b', 'c', 'd', 'e', 'f'];

let B = A.reduceRight((a, c) => (a.push(c), a), []);

console.log(B);

有用的资源:

【讨论】:

  • reduceRight 很慢
  • @DragosRizescu 你能分享一些样本测试结果吗?
  • 这里有一个你可以玩的 repo:(不是最好的例子,但不久前在 React 上下文中与某人有过这个论点,因此我把它放在一起):github.com/rizedr/reduce-vs-reduceRight
  • (a, c) => a.concat([c]) 感觉比(a, c) => (a.push(c), a) 更地道
  • @DragosRizescu 实际上看起来这是 3 个热门答案中最快的。 jsperf.com/reverse-vs-slice-reverse/3
【解决方案4】:

试试这个递归解决方案:

const reverse = ([head, ...tail]) => 
    tail.length === 0
        ? [head]                       // Base case -- cannot reverse a single element.
        : [...reverse(tail), head]     // Recursive case

reverse([1]);               // [1]
reverse([1,2,3]);           // [3,2,1]
reverse('hello').join('');  // 'olleh' -- Strings too!                              

【讨论】:

  • 这看起来会因为空数组而中断。
【解决方案5】:

使用 .reduce() 和传播的 ES6 替代方案。

const foo = [1, 2, 3, 4];
const bar = foo.reduce((acc, b) => ([b, ...acc]), []);

基本上它的作用是用 foo 中的下一个元素创建一个新数组,并在 b 之后为每次迭代传播累积的数组。

[]
[1] => [1]
[2, ...[1]] => [2, 1]
[3, ...[2, 1]] => [3, 2, 1]
[4, ...[3, 2, 1]] => [4, 3, 2, 1]

或者.reduceRight() 如上所述,但没有.push() 突变。

const baz = foo.reduceRight((acc, b) => ([...acc, b]), []);

【讨论】:

    【解决方案6】:

    有多种方法可以在不修改的情况下反转数组。其中两个是

    var array = [1,2,3,4,5,6,7,8,9,10];
    
    // Using Splice
    var reverseArray1 = array.splice().reverse(); // Fastest
    
    // Using spread operator
    var reverseArray2 = [...array].reverse();
    
    // Using for loop 
    var reverseArray3 = []; 
    for(var i = array.length-1; i>=0; i--) {
      reverseArray.push(array[i]);
    }
    

    性能测试http://jsben.ch/guftu

    【讨论】:

    • 您所写的array.splice()slice() 方法之间是否存在性能差异?
    • 应该是slice() 而不是splice()。后者返回一个空数组。
    【解决方案7】:
    const arrayCopy = Object.assign([], array).reverse()
    

    这个解决方案:

    -成功复制数组

    -不改变原始数组

    -看起来它正在做它正在做的事情

    【讨论】:

      【解决方案8】:

      仅出于演示目的使用变量交换进行反转(但如果您不想变异,则需要一份副本)

      const myArr = ["a", "b", "c", "d"];
      const copy = [...myArr];
      for (let i = 0; i < (copy.length - 1) / 2; i++) {  
          const lastIndex = copy.length - 1 - i; 
          [copy[i], copy[lastIndex]] = [copy[lastIndex], copy[i]] 
      }
      
      

      【讨论】:

        【解决方案9】:

        虽然array.slice().reverse() 是在我无法使用库的情况下我自己会选择的,但它在可读性方面并不是那么好:我们使用的是命令式逻辑,阅读代码的人必须仔细考虑。考虑到sort 也存在同样的问题,这里有充分的理由使用实用程序库。

        您可以使用来自fp-tsa library I've written myself 的函数pipe。它通过多个函数传递一个值,因此pipe(x, a, b) 等价于b(a(x))。有了这个函数,你可以写

        pipe(yourArray, reverseArray)
        

        其中reverseArray 是一个基本上执行.slice().reverse() 的函数,即不可变地反转数组。一般来说,pipe 可以让你做点链接的等价物,但不限于数组原型上可用的方法。

        【讨论】:

          【解决方案10】:

          进入纯 Javascript:

          function reverseArray(arr, num) {
            var newArray = [];
            for (let i = num; i <= arr.length - 1; i++) {
              newArray.push(arr[i]);
            }
          
            return newArray;
          }
          

          【讨论】:

            【解决方案11】:

            es6:

            const reverseArr = [1,2,3,4].sort(()=>1)
            

            【讨论】:

            • 欢迎来到 SO,Radion!留下答案时,通常最好解释一下您的答案为何有效以及为什么得出此结论,这有助于新用户了解您指定的交互方式和语言。
            • 在 Radion 的辩护中:P 最后的1 可能大于零,因为这就是Array.prototype.sort 回调(或所谓的compare function)的工作方式。基本上你总是比较两个数字,在这种情况下,比较总是返回正数,所以它说总是移动到第一个数字前面的第二个数字:) 这很容易解释:stackoverflow.com/questions/6567941/…
            • sort() 对数组进行变异(即对其进行排序),这是 OP 想要避免的。
            • 这个答案在几个方面是错误的。 (1) 正如@ClintHarris 指出的那样,它会改变数组,所以它并不比.reverse() 好。 (2) 你的比较器是非法的——当你为 a,b 返回 1 时,你必须为 b,a 返回一个负数。如果您的答案在某些实现中反转了数组,那完全是靠运气。
            猜你喜欢
            • 2020-04-07
            • 2020-05-22
            • 1970-01-01
            • 1970-01-01
            • 2018-03-16
            • 2021-12-28
            • 2019-03-11
            相关资源
            最近更新 更多