2010-07-21 61 views
13

Giả sử tôi có một danh sách các thứ (số, để giữ mọi thứ đơn giản ở đây) và tôi có một hàm tôi muốn sử dụng để sắp xếp chúng bằng cách sử dụng SortBy. Ví dụ, sau đây sắp xếp một danh sách các số bằng chữ số cuối cùng:Phân loại ổn định, tức là phân loại tối thiểu

SortBy[{301, 201}, Mod[#,10]&] 

Và hãy chú ý cách hai (ví dụ, tất cả) những con số có cùng chữ số cuối cùng. Vì vậy, nó không quan trọng mà trật tự chúng tôi trả lại cho họ. Trong trường hợp này Mathematica trả về chúng theo thứ tự ngược lại. Làm cách nào để đảm bảo rằng tất cả các mối quan hệ đều bị hỏng trong việc ưu tiên các mục được đặt hàng trong danh sách gốc?

(Tôi biết đó là loại tầm thường nhưng tôi cảm thấy như thế này đi lên theo thời gian vì vậy tôi nghĩ rằng nó sẽ là tiện dụng để có được nó trên StackOverflow. Tôi sẽ đăng bất cứ điều gì tôi đưa ra như là một câu trả lời nếu không có ai đánh bại tôi với nó.)

Cố gắng thực hiện điều này dễ tìm kiếm hơn: sắp xếp với ít nhiễu nhất, sắp xếp ít nhất số lần hoán đổi, tùy chỉnh vi phạm, phân loại với trao đổi tốn kém, phân loại ổn định.

PS: Nhờ Nicholas để chỉ ra rằng đây được gọi là sắp xếp ổn định. Nó ở trên đầu lưỡi tôi! Đây một đường link khác: http://planetmath.org/encyclopedia/StableSortingAlgorithm.html

+2

Điều không được tìm kiếm ở đây thường chỉ được gọi là thuật toán sắp xếp ổn định? Xem: http://en.wikipedia.org/wiki/Sorting_algorithm#Stability –

Trả lời

16

Sau khi hỏi xung quanh, tôi đã được giải thích thỏa mãn:

Câu trả lời ngắn: Bạn muốn SortBy[list, {f}] để có được loại ổn định.

Long trả lời:

SortBy[list, f] cả các loại danh sách theo thứ tự xác định bằng cách áp dụng f để mỗi phần tử của danh sách, quan hệ vi phạm sử dụng trật tự kinh điển giải thích dưới Sắp xếp. (Đây là ghi chú "Thông tin Bổ sung" được ghi lại lần thứ hai trong số documentation for SortBy.)

SortBy[list, {f, g}] ngắt liên kết bằng cách sử dụng thứ tự được xác định bằng cách áp dụng g cho từng phần tử.

Lưu ý rằng SortBy[list, f] giống với SortBy[list, {f, Identity}].

SortBy[list, {f}] làm không phá vỡ tie (và đưa ra một loại ổn định), đó là những gì bạn muốn:

In[13]:= SortBy[{19, 301, 201, 502, 501, 101, 300}, {Mod[#, 10] &}] 

Out[13]= {300, 301, 201, 501, 101, 502, 19} 

Cuối cùng, Sakra của giải pháp SortBy[list, {f, tie++ &}] là có hiệu quả tương đương với SortBy[list, {f}].

+0

Ồ, cảm ơn, Andrew! Tôi đọc điều này và giống như "bạn vừa hỏi xung quanh? Bạn làm việc ở đâu, Wolfram Research?" Sau đó, tôi nhấp vào tên của bạn và thấy rằng thực sự bạn làm. :) Tôi liên tục ngạc nhiên trước mức độ chuyên môn mà StackOverflow thu hút. Cảm ơn rất nhiều vì đã đến đây! – dreeves

2

Điều này dường như làm việc:

stableSortBy[list_, f_] := 
    SortBy[MapIndexed[List, list], {[email protected][#], Last[#]}&][[All,1]] 

Nhưng bây giờ tôi thấy rosettacode đưa ra một cách rất đẹp làm:

stableSortBy[list_, f_] := list[[Ordering[f /@ list]]] 

Vì vậy, đặt hàng chính là chìa khóa! Có vẻ như tài liệu Mathematica không đề cập đến sự khác biệt quan trọng này khi sắp xếp và sắp xếp thứ tự.

+1

Cách tiếp cận này được gọi là thành ngữ "trang trí-sắp xếp-undecorate" trong vòng tròn Lisp, và thậm chí nếu 'GatherBy' có thể là cách tiếp cận tốt nhất để phân loại ổn định trong đặc biệt, nó là một thủ thuật phi thường hữu ích trong Mathematica. – Pillsy

+1

Tôi muốn tò mò về cách ngăn xếp này chống lại 'GatherBy' về tốc độ, và nó sẽ phụ thuộc vào cách danh sách được thực hiện trong nội bộ. Vấn đề của tôi là 'GatherBy' chỉ có thể chạm vào từng phần tử danh sách một lần, trong khi giải pháp' Ordering' sẽ yêu cầu ít nhất hai lần: một lần cho sắp xếp và một lần cho việc sắp xếp lại các phần tử. Đối với các danh sách nhỏ, nó có thể không quan trọng. Nhưng, mà không thực sự làm điều đó, tôi nghi ngờ rằng đối với các danh sách dài hơn 'GatherBy' sẽ mang lại hiệu năng cao. – rcollyer

+0

PS: Tôi nghĩ rằng đây là tất cả các tranh luận trong ánh sáng của câu trả lời được chấp nhận. – dreeves

6

GatherBy có làm những gì bạn muốn không?

Flatten[GatherBy[{301, 201, 502, 501, 101}, Mod[#, 10] &]] 
+1

Ồ, có thể, cảm ơn! Tôi đã không nghĩ đến việc sử dụng GatherBy. Tôi có xu hướng đi với giải pháp Đặt hàng. Nếu bạn tò mò và muốn so sánh các giải pháp cho đến nay với các bài kiểm tra Timing, tôi sẽ làm cho bạn trở thành câu trả lời được chấp nhận. (Oh, một vấn đề với giải pháp của bạn: bạn nên làm Flatten [..., 1] nếu không, nếu các yếu tố thực sự được liệt kê thì Flatten sẽ làm hỏng chúng.) – dreeves

+0

PS: Tôi nghĩ rằng điều này bây giờ là tranh luận trong ánh sáng của câu trả lời được chấp nhận . – dreeves

4

Có một biến thể của SortBy mà phá vỡ mối quan hệ bằng cách sử dụng thêm chức năng đặt hàng:

SortBy[list,{f1, f2, ...}]

Bằng cách đếm các mối quan hệ như vậy, bạn có thể lấy một sắp xếp ổn định:

Module[{tie = 0}, 
SortBy[{19, 301, 201, 502, 501, 101, 300}, {Mod[#, 10] &, (tie++) &}]] 

sản lượng

{300, 301, 201, 501, 101, 502, 19} 
+0

Cảm ơn, tôi đã không biết điều đó! Hóa ra nó thậm chí còn đơn giản hơn, như câu trả lời được chấp nhận cho thấy. – dreeves