Đảo ngược mảng trong Javascript mà không làm thay đổi mảng gốc


188

Array.prototype.reverse đảo ngược nội dung của một mảng tại chỗ (có đột biến) ...

Có một chiến lược đơn giản tương tự để đảo ngược một mảng mà không làm thay đổi nội dung của mảng ban đầu (không có đột biến) không?



Dưới đây là điểm chuẩn so sánh các tùy chọn khác nhau: jsben.ch/HZ7Zp
Solomon Ucko

Câu trả lời:


375

Bạn có thể sử dụng lát () để tạo một bản sao rồi đảo ngược ()

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


Bạn có thể vui lòng khám phá lát () không có tham số không?
Alex

3
@Alex lát - If begin is omitted, slice begins from index 0.- vì vậy nó giống nhưarray.slice(0)
Arun P Johny

2
Tôi nghĩ @Alex có nghĩa là 'giải thích nó trong câu trả lời của bạn' ... bất kể ... Giải pháp tuyệt vời. Cảm ơn!
sfletche

13
Tôi KHÔNG khuyên bạn nên sử dụng phương pháp này, vì nó rất dễ gây hiểu lầm. Thật khó hiểu khi bạn sử dụng lát () và bạn thực sự không cắt bất cứ thứ gì. Nếu bạn cần đảo ngược bất biến, chỉ cần tạo bản sao mới: const newArray = [... mảng] .reverse ()
Oleg Matei

105

Trong ES6:

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

2
Làm thế nào để hiệu suất của điều này so với câu trả lời được chấp nhận? Họ có giống nhau không?
Katie

@Katie Rất giống nhau, cả hai đều rất nhanh, với Chrome dường như mang lại [...].reverselợi thế trong trường hợp thử nghiệm rất đơn giản. jsperf.com/reverse-vs-slice-reverse/1
Brian M. Hunt

4
Tôi liên tục nhận được .slicenhanh hơn đáng kể.
James Coyle

3
@JamesCoyle Có thể phụ thuộc vào trình duyệt và hệ điều hành, nhưng slicecó khả năng nhanh hơn b / c [...]là một mảng lặp có thể lặp chung nên không thể đưa ra nhiều giả định. Đồng thời, nó có khả năng sliceđược tối ưu hóa tốt hơn bởi vì nó đã xuất hiện từ lâu.
Brian M. Hunt

Suy nghĩ của tôi chính xác.
James Coyle

11

Một biến thể ES6 khác:

Chúng ta cũng có thể sử dụng .reduceRight()để tạo ra một mảng đảo ngược mà không thực sự đảo ngược nó.

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

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

console.log(B);

Tài nguyên hữu ích:


2
reduceRightchậm af
Dragos Rizescu

@DragosRizescu Bạn có thể chia sẻ một số kết quả kiểm tra mẫu không?
Mohammad Usman

1
Đây là một repo mà bạn có thể chơi với: (không phải là ví dụ tốt nhất, nhưng đã lập luận này với một ai đó trong một thời gian trước đây trong một bối cảnh Phản ứng, vì vậy tôi đã đặt nó lại với nhau): github.com/rizedr/reduce-vs-reduceRight
Dragos Rizescu

4
(a, c) => a.concat([c])cảm thấy thành ngữ hơn(a, c) => (a.push(c), a)
Kyle Lin

1
@DragosRizescu nó thực sự có vẻ như đây là câu trả lời nhanh nhất trong số 3 câu trả lời hàng đầu. jsperf.com/reverse-vs-slice-reverse/3
DBosley

7

Hãy thử giải pháp đệ quy này:

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!                              

1
Điều này có vẻ như nó sẽ phá vỡ cho các mảng trống.
Matthias

6

Một thay thế ES6 sử dụng .reduce()và lan rộng.

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

Về cơ bản những gì nó làm là tạo ra một mảng mới với phần tử tiếp theo trong foo và trải rộng mảng tích lũy cho mỗi lần lặp sau b.

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

Hoặc .reduceRight()như đã đề cập ở trên, nhưng không có .push()đột biến.

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

4

Có nhiều cách để đảo ngược một mảng mà không sửa đổi. Hai trong số họ là

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

Kiểm tra hiệu suất http://jsben.ch/guftu


0

VÀO Javascript đơn giản:

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

  return newArray;
}

0

Đảo ngược tại chỗ với hoán đổi biến đổi chỉ nhằm mục đích trình diễn (nhưng bạn cần một bản sao nếu bạn không muốn thay đổi)

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


-4

es6:

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

4
Chào mừng đến với SO, Radion! Khi để lại câu trả lời, thông thường nên giải thích lý do tại sao câu trả lời của bạn hoạt động và tại sao bạn đi đến kết luận này, điều này giúp người dùng mới hơn hiểu được các tương tác và ngôn ngữ bạn đã chỉ định.
Cánh đồng Ethan

Trong phòng thủ của Radion: P rằng 1cuối cùng có thể là bất cứ thứ gì lớn hơn 0, bởi vì đó là cách Array.prototype.sortgọi lại (hay còn gọi là compare function) hoạt động. Về cơ bản, bạn luôn so sánh 2 số và trong trường hợp này, giá trị so sánh luôn luôn dương, do đó, nó luôn luôn chuyển sang số thứ hai trước số thứ nhất :) điều này rất dễ giải thích: stackoverflow.com/questions/6567941/
đấm

8
sort()làm thay đổi mảng (nghĩa là sắp xếp nó đúng chỗ), đó là điều mà OP muốn tránh.
Clint Harris

5
Câu trả lời này là sai theo nhiều cách. (1) nó làm thay đổi mảng, như @ClintHarris chỉ ra, vì vậy nó không tốt hơn .reverse (). (2) bộ so sánh của bạn là bất hợp pháp-- khi bạn trả về 1 cho a, b, bạn phải trả về số âm cho b, a. Nếu câu trả lời của bạn đảo ngược mảng trên một số triển khai, thì đó hoàn toàn là do may mắn.
Don nở
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.