Làm thế nào bạn có thể sắp xếp một mảng mà không làm thay đổi mảng ban đầu?


230

Giả sử tôi muốn một hàm sắp xếp trả về một bản sao đã sắp xếp của mảng được nhập. Tôi ngây thơ thử cái này

function sort(arr) {
  return arr.sort();
}

và tôi đã thử nó với điều này, cho thấy sortphương thức của tôi đang làm biến đổi mảng.

var a = [2,3,7,5,3,7,1,3,4];
sort(a);
alert(a);  //alerts "1,2,3,3,3,4,5,7,7"

Tôi cũng đã thử phương pháp này

function sort(arr) {
  return Array.prototype.sort(arr);
}

nhưng nó không hoạt động.

Có cách nào đơn giản để giải quyết vấn đề này không, tốt nhất là cách không yêu cầu tự tay thực hiện thuật toán sắp xếp của riêng tôi hoặc sao chép mọi phần tử của mảng vào một cái mới?


1
tạo một bản sao sâu của mảng và sắp xếp nó thay thế.
evanmcdonnal

1
@evanmcdonnal Một bản sao nông có thể đủ tốt nếu tất cả những gì muốn là một sự sắp xếp lại và không phải là một bản sao của mỗi mục trong mảng.
Kekoa

.sortyêu cầu thisgiá trị là mảng, vì vậy để đoạn mã cuối cùng hoạt động bạn sẽ làm .sort.call(arr)(mặc dù nó không giải quyết được vấn đề của bạn).
pimvdb

@Kekoa Vâng đó là một điểm tốt. Không cần tiêu thụ thêm bộ nhớ nếu bạn chỉ thay đổi thứ tự của các phần tử chứ không phải chính các phần tử.
evanmcdonnal

Phương pháp của zzzzBov đang hoạt động như một cơ duyên! stackoverflow.com/a/9592774/7011860
Samet M.

Câu trả lời:


222

Chỉ cần sao chép mảng. Có nhiều cách để làm điều đó:

function sort(arr) {
  return arr.concat().sort();
}

// Or:
return Array.prototype.slice.call(arr).sort(); // For array-like objects

2
Điều này sẽ làm một bản sao sâu, tức là, các đối tượng và mảng lồng nhau cũng sẽ được sao chép?
Peter Olson

2
Có bất kỳ lợi thế nào khi sử dụng concathơn nói slice(0)hay tất cả đều giống nhau không?
JaredPar

3
@PeterOlson Không, đó là một bản sao nông. Nếu bạn thực sự muốn có một bản sao sâu, hãy sử dụng tính năng tìm kiếm trên Stack Overflow để tìm câu trả lời xuất sắc cho điều đó.
Rob W

11
Slice hiện được báo cáo là nhanh hơn đáng kể
Zander Brown

3
Tại sao Array.prototype.slice.call(arr).sort();thay vì arr.slice().sort();?
Olivier Boissé


61

Hãy thử như sau

function sortCopy(arr) { 
  return arr.slice(0).sort();
}

Các slice(0)biểu hiện tạo ra một bản sao của mảng bắt đầu tại phần tử 0.


32

Bạn có thể sử dụng lát cắt không có đối số để sao chép một mảng:

var foo,
    bar;
foo = [3,1,2];
bar = foo.slice().sort();

Câu trả lời này thật tuyệt vời! Tôi ngạc nhiên khi JavaScript cho phép đột biến ở mức độ này. Có vẻ sai. Cảm ơn, một lần nữa.

12

Bạn cũng có thể làm điều này

d = [20, 30, 10]
e = Array.from(d)
e.sort()

Cách này d sẽ không bị đột biến.

function sorted(arr) {
  temp = Array.from(arr)
  return temp.sort()
}

//Use it like this
x = [20, 10, 100]
console.log(sorted(x))

Câu trả lời này rất hay
Leasye

1

Bất cứ ai muốn làm một bản sao sâu (ví dụ nếu mảng của bạn chứa các đối tượng) có thể sử dụng:

let arrCopy = JSON.parse(JSON.stringify(arr))

Sau đó, bạn có thể sắp xếp arrCopymà không thay đổi arr.

arrCopy.sort((obj1, obj2) => obj1.id > obj2.id)

Xin lưu ý: điều này có thể chậm đối với các mảng rất lớn.


Điều này sẽ làm việc với -thay vì >trong ví dụ thứ hai của bạn.
pootzko

0

Tôi sử dụng Object.assign () cho hầu hết các bản sao của mình:

var copyArray = Object.assign([], originalArray).sort();

Tuy nhiên, sau khi xem qua các bình luận của OP, tôi đã nghiên cứu một chút sao chép sâu và hóa ra Object.assign không chỉ thực hiện một bản sao nông, mà còn chỉ chọn vô số và thuộc tính riêng (như đã trả lời trong bài đăng này ).

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.