【发布时间】:2015-08-17 02:21:15
【问题描述】:
Array.prototype.reverse 反转原地数组的内容(带有突变)...
是否有类似的简单策略来反转数组而不改变原始数组的内容(不改变)?
【问题讨论】:
-
这是一个比较不同选项的基准:jsben.ch/HZ7Zp
标签: javascript arrays
Array.prototype.reverse 反转原地数组的内容(带有突变)...
是否有类似的简单策略来反转数组而不改变原始数组的内容(不改变)?
【问题讨论】:
标签: javascript arrays
【讨论】:
If begin is omitted, slice begins from index 0. - 所以和array.slice(0)一样
Array#slice 的作用,就不会感到困惑。传播语法没有理由不那么令人困惑。
在 ES6 中:
const newArray = [...array].reverse()
【讨论】:
.slice 的速度明显更快。
slice 可能更快 b/c [...] 是一个通用的可迭代数组,因此不能做出尽可能多的假设。同样,slice 可能会更好地优化 b/c 它已经存在很长时间了。
另一个 ES6 变体:
我们还可以使用.reduceRight() 创建一个反转数组,而无需实际反转它。
let A = ['a', 'b', 'c', 'd', 'e', 'f'];
let B = A.reduceRight((a, c) => (a.push(c), a), []);
console.log(B);
有用的资源:
【讨论】:
reduceRight 很慢
(a, c) => a.concat([c]) 感觉比(a, c) => (a.push(c), a) 更地道
试试这个递归解决方案:
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!
【讨论】:
使用 .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]), []);
【讨论】:
有多种方法可以在不修改的情况下反转数组。其中两个是
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]);
}
【讨论】:
array.splice() 与slice() 方法之间是否存在性能差异?
slice() 而不是splice()。后者返回一个空数组。
const arrayCopy = Object.assign([], array).reverse()
这个解决方案:
-成功复制数组
-不改变原始数组
-看起来它正在做它正在做的事情
【讨论】:
仅出于演示目的使用变量交换进行反转(但如果您不想变异,则需要一份副本)
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]]
}
【讨论】:
虽然array.slice().reverse() 是在我无法使用库的情况下我自己会选择的,但它在可读性方面并不是那么好:我们使用的是命令式逻辑,阅读代码的人必须仔细考虑。考虑到sort 也存在同样的问题,这里有充分的理由使用实用程序库。
您可以使用来自fp-ts 或a library I've written myself 的函数pipe。它通过多个函数传递一个值,因此pipe(x, a, b) 等价于b(a(x))。有了这个函数,你可以写
pipe(yourArray, reverseArray)
其中reverseArray 是一个基本上执行.slice().reverse() 的函数,即不可变地反转数组。一般来说,pipe 可以让你做点链接的等价物,但不限于数组原型上可用的方法。
【讨论】:
进入纯 Javascript:
function reverseArray(arr, num) {
var newArray = [];
for (let i = num; i <= arr.length - 1; i++) {
newArray.push(arr[i]);
}
return newArray;
}
【讨论】:
es6:
const reverseArr = [1,2,3,4].sort(()=>1)
【讨论】:
1 可能大于零,因为这就是Array.prototype.sort 回调(或所谓的compare function)的工作方式。基本上你总是比较两个数字,在这种情况下,比较总是返回正数,所以它说总是移动到第一个数字前面的第二个数字:) 这很容易解释:stackoverflow.com/questions/6567941/…
sort() 对数组进行变异(即对其进行排序),这是 OP 想要避免的。