2013-08-16 28 views
6

Tôi có một số Array của Array mà tôi muốn sắp xếp theo độ dài dài nhất đến ngắn nhất. Tôi đạt được điều này một cách dễ dàng đủ với một sort_bySắp xếp Mảng Mảng theo chiều dài với mã vạch

> a = [ [1, 2, 9], 
     [4, 5, 6, 7], 
     [1, 2, 3] ] 
> a.sort_by(&:length).reverse # or a.sort_by {|e| e.length}.reverse 
=> [[4, 5, 6, 7], [1, 2, 3], [1, 2, 9]] 

Những gì tôi muốn, tuy nhiên là phải có một loại tie-breaker cho danh sách dài bằng nhau. Nếu độ dài của hai danh sách bằng nhau, danh sách có mục nhập cuối cùng là lớn hơn sẽ đến trước. Vì vậy, ở trên, [1, 2, 9][1, 2, 3] phải được chuyển.

Tôi không quan tâm đến trường hợp hai danh sách có cả chiều dài bằng nhau và phần tử cuối cùng bằng nhau, chúng có thể theo thứ tự bất kỳ nếu điều đó xảy ra. Tôi không biết nếu/làm thế nào tôi có thể đạt được điều này với ruby ​​được xây dựng trong phân loại.

+0

Sử dụng một khối, như trong ví dụ trong tài liệu: http://www.ruby-doc.org/core-2.0/Enumerable.html#method-i-sort_by – SheetJS

Trả lời

12

Bạn vẫn có thể làm điều này với sort_by, bạn chỉ cần nhận ra rằng Ruby arrays compare element-by-element:

ary < => other_ary → -1, 0, +1 hoặc nil

[.. .]

Mỗi đối tượng trong mỗi mảng được so sánh (sử dụng toán tử < =>).

Mảng được so sánh theo cách “theo nguyên tố”; hai phần tử đầu tiên không bằng nhau sẽ xác định giá trị trả về cho toàn bộ so sánh.

Điều đó có nghĩa rằng bạn có thể sử dụng các mảng như là chìa khóa sort_by, sau đó ném vào một chút phủ số nguyên để đảo ngược thứ tự sắp xếp và bạn nhận được:

a.sort_by { |e| [-e.length, -e.last] } 

Điều đó sẽ cung cấp cho bạn [[4, 5, 6, 7], [1, 2, 9], [1, 2, 3]] mà bạn 'Đang tìm kiếm.

Nếu bạn không sử dụng số để mẹo "phủ định đảo ngược thứ tự" sẽ không hoạt động, hãy sử dụng phương thức Shaunak's sort.

+0

Câu trả lời hay, mặc dù nó có vẻ bình thường thành thạo Rubyists. –

+0

@BorisStitnicky: Cảm ơn.Tôi thực sự thấy rằng như một giải pháp lấy cảm hứng từ SQL, đó là khá nhiều phiên âm của 'thứ tự theo chiều dài desc, desc' cuối cùng (ngoại trừ phiên bản SQL sẽ hoạt động tốt với chuỗi vì nó không phụ thuộc vào" phủ định đảo ngược thứ tự " lừa). –

+0

Câu trả lời hay nhất @muistooshort. Ngoài sự tò mò, liệu có sự khác biệt về tính toán giữa giải pháp của bạn sẽ so sánh với tôi như thế nào? đặc biệt là nếu các mảng quá lớn và phức tạp? Tôi không chắc chắn làm thế nào sory_by thực hiện khối của nó sẽ nó sắp xếp hai lần hoặc như trong giải pháp của tôi nó chỉ sửa đổi so sánh trong cùng một đi. – Shaunak

3

Có bạn đi:

a = [ [1, 2, 9],[4, 5, 6, 7],[1, 2, 3] ] 
a.sort { |a, b| (b.count <=> a.count) == 0 ? (b.last <=> a.last): (b.count <=> a.count) } 

Điều đó sẽ cung cấp cho bạn:

[[4, 5, 6, 7], [1, 2, 9], [1, 2, 3]] 

Cách hoạt động: chúng ta vượt qua một khối để sắp xếp chức năng, trong đó kiểm tra đầu tiên nếu chiều dài mảng là cùng, nếu không phải nó tiếp tục kiểm tra yếu tố cuối cùng.

+2

Tôi nghĩ rằng '(a.length == b.length)' cho điều kiện đầu tiên sẽ phù hợp hơn với lời giải thích của bạn 'nếu chiều dài mảng là giống nhau'. –

+0

không chắc chắn ý bạn là gì, bạn có thể viết xuống không? – Shaunak

+0

Tất cả tôi, gợi ý là: '(a.length == b.length)?' Thay vì '(b.count <=> a.count) == 0? ' –

2

Bạn có thể sử dụng

a.sort_by {|i| [i.length, i.last] }.reverse 
# => [[4, 5, 6, 7], [1, 2, 9], [1, 2, 3]]