The Ultimate Guide to Ruby Sorting
Bài đăng này đã không được cập nhật trong 7 năm
Có bao nhiêu cách để sắp xếp mảng trong Ruby
Mặc dù Array
chỉ có 2 methods sắp xếp là sort & sort_by
, nhưng các method này có thể kết hợp sử dụng với block
để cho ra nhiều cách sắp xếp khác nhau.
Tôi muốn chia sẻ với các bạn 1 số ví dụ trong bài viết này.
Và bạn cũng có thể thực hiện một phương thức sắp xếp của bạn sử dụng thuật toán quick-sort ở cuối bài.
Basic Sorting
Method cơ bản nhất của việc sắp xếp trong Ruby
là sort
. Nó được định nghĩa trong Enumerable module
numbers = [5,3,2,1]
numbers.sort
# [1,2,3,5]
sort
trả về kết quả là một mảng mới.
Hoặc có thể dùng sort!
để sửa ngay trên mảng hiện tại mà không tạo ra mảng mới.
Customized Sorting
Bây giờ chúng ta hãy xem loại sắp xếp nâng cao hơn một chút.
Với sort_by
strings = %w(foo test blog a)
strings.sort_by(&:length)
# ["a", "foo", "test", "blog"]
Hoặc sort
strings = %w(foo test blog a)
strings.sort { |a,b| a.length <=> b.length }
# ["a", "foo", "test", "blog"]
Ở đây mình khuyên dùng sort_by
bởi vì nhìn rõ ràng hơn và tốc độ có nhanh hơn một chút.
Reverse Sort
Để reverse sort bạn có thể sử dụng reverse
method sau khi sorting.
Hoặc 1 cách khác như sau.
strings = %w(foo test blog a)
strings.sort_by { |str| -str.length }
# ["blog", "test", "foo", "a"]
Alphanumeric Sorting
Bạn muốn sắp xếp 1 mảng các string có chứa numbers
music = %w(21.mp3 10.mp3 5.mp3 40.mp3)
Sử dụng method sort
music.sort
# ["10.mp3", "21.mp3", "40.mp3", "5.mp3"]
Đây không phải là kết qủa chúng ta mong đợi. Đây là cách chúng ta sắp xếp với trường hợp này.
music.sort_by { |s| s.scan(/\d+/).first.to_i }
# ["5.mp3", "10.mp3", "21.mp3", "40.mp3"]
Sorting Hashes
Chúng ta cũng có thể sort trên hash tương tự như với array.
hash = {coconut: 200, orange: 50, bacon: 100}
hash.sort_by(&:last)
# [[:orange, 50], [:bacon, 100], [:coconut, 200]]
Kết quả sắp xếp đúng và trả về dạng mảng đa chiều. Chúng ta có thể chuyển về dạng hash bằng cách sử dụng Array#to_h
QuickSort Implementation
Bây giờ chúng ta sẽ implement 1 phương thức sắp xếp riêng của chúng ta, có thể sẽ chậm hơn method sort
, nhưng nó sẽ khá thú vị để học.
def quick_sort(list)
qsort_helper(list).flatten
end
def qsort_helper(list)
return [] if list.empty?
number = list.sample
lower, higher = list.partition { |n| n < number }
higher.delete_at(higher.index(number))
[qsort_helper(lower), number, qsort_helper(higher)]
end
p quick_sort [3, 7, 2, 1, 8, 12]
# [1, 2, 3, 7, 8, 12]
Ý tưởng của Quick sort
là chọn ngẫu nhiên 1 số M trong mảng, chia mảng thành 2 phần. 1 phần có các giá trị nhỏ hơn M và 1 phần có giá trị lớn hơn hoặc bằng M.
Và sẽ tiếp tục lặp lại quá trình này cho tới khi mảng được sắp xếp.
Benchmarks
Bây giờ ta sẽ so sánh tốc độ của các method sắp xếp ở phiên bản ruby 2.4.0
sort!: 1405.8 i/s
sort: 1377.6 i/s - same-ish: difference falls within error
sort_by reverse: 196.6 i/s - 7.15x slower
sort_by: 183.7 i/s - 7.65x slower
sort_by minus: 172.3 i/s - 8.16x slower
sort with block: 164.1 i/s - 8.57x slower
=> sort
nhanh hơn sort_by
nhưng nó sẽ kém linh hoạt nếu ban không dùng block
Bài viết được dịch tại:
All rights reserved