在 Javascript 中不改变原始数组的反向数组

Array.prototype.reverse在适当的位置反转数组的内容(带有变异) ..。

有没有一种类似的简单策略,可以在不改变原始数组内容(不变异)的情况下逆转数组?

124955 次浏览

你可以使用片()创建一个副本,然后反向()

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

在ES6:

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

es6:

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

ES6的另一个变体:

我们也可以使用.reduceRight()来创建一个反向数组,而不实际将其反向。

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


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


console.log(B);

有用的资源:

ES6替代方案,使用.reduce()和扩展。

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

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

试试这个递归解决方案:

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!

进入纯Javascript:

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


return newArray;
}

仅出于演示目的,使用变量交换进行反向(但如果不想发生变化,则需要一个副本)

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一个我自己写的库中使用函数pipe。它通过许多函数传递一个值,因此pipe(x, a, b)等价于b(a(x))。使用这个函数,您可以编写

pipe(yourArray, reverseArray)

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

const arrayCopy = Object.assign([], array).reverse()

这个解决方案:

-成功复制array

-不会改变原始数组

-看起来它在做它该做的事

const newArr = Array.from(originalArray).reverse();

有一个新的tc39提议,它向Array添加了一个toReversed方法,该方法返回数组的副本,并且不修改原始数组。

提案示例:

const sequence = [1, 2, 3];
sequence.toReversed(); // => [3, 2, 1]
sequence; // => [1, 2, 3]

由于它目前处于第3阶段,可能很快就会在浏览器引擎中实现,但与此同时,在在这里core-js中可以使用polyfill。

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

是的,有一种方法可以通过使用to[Operation]来实现这一点,它返回一个带有应用操作的新集合(这目前处于阶段3,很快就会可用)。

实现将像一样

const arr = [5, 4, 3, 2, 1];


const reversedArr = arr.toReverse();


console.log(arr); // [5, 4, 3, 2, 1]


console.log(reversedArr); // [1, 2, 3, 4, 5]

进入2022年,这是当今最高效的解决方案(性能最高,并且没有额外的内存占用)。


对于任何ArrayLike类型,逻辑上最快的反转方法是将其包装为反转的可迭代对象:

function reverse<T>(input: ArrayLike<T>): Iterable<T> {
return {
[Symbol.iterator](): Iterator<T> {
let i = input.length;
return {
next(): IteratorResult<T> {
return i
? {value: input[--i], done: false}
: {value: undefined, done: true};
},
};
},
};
}

通过这种方式,你可以通过任意ArraystringBuffer进行反向迭代,而无需对反向数据进行任何额外的复制或处理:

for(const a of reverse([1, 2, 3])) {
console.log(a); //=> 3 2 1
}

这是最快的方法,因为你不复制数据,也不做任何处理,你只是在逻辑上反向。