2009-07-28 37 views
19

Tôi có một mảng của mảng như sau:Sorting một mảng của mảng trong Ruby

irb(main):028:0> device_array 
=> [["name1", "type1", ["A", "N", "N"], ["Attribute", "device_attribute"], 9], ["name2","type2", ["A", "N", "N"], ["Attribute", "device_attribute"], 7]] 

Tôi muốn sắp xếp toàn bộ device_array trên các yếu tố thứ 4.

Tôi đã thử

AllDevicesController.all_devices.sort do | a,b | 
    for i in 0..(AllDevicesController.all_devices.length - 1) do 
    a[i][4] <=> b[i][4] 
    end 
end 

Tôi cũng đã thử:

AllDevicesController.all_devices.sort do | a,b | 
    a[][4] <=> b[][4] 
end 

Cả hai phương pháp chưa từng làm việc.

Tôi đã sử dụng điều này như một tài liệu tham khảo: http://ariejan.net/2007/01/28/ruby-sort-an-array-of-objects-by-an-attribute/

Tôi tưởng tượng tôi là thiếu một cái gì đó rubyish mà làm cho điều này thực sự dễ dàng.

Trả lời

22

Bạn không thể sử dụng <=> với nil.

Mã của bạn nên có một cái gì đó như thế này:

AllDevicesController.all_devices.sort do |a, b| 
    a[4].nil? ? -1 : b[4].nil? ? 1 : a[4] <=> b[4] 
end 

Điều này sẽ đặt các tiểu mảng mà không có yếu tố của chỉ số 4 vào lúc bắt đầu của kết quả. Để thực hiện theo cách khác, hãy trao đổi -1 với 1.

Bạn cũng có thể sử dụng sort_by thay vì sort. Tôi nghĩ rằng điều này đã được giới thiệu trong Ruby 1.8.7 (vì vậy nó có thể không hoạt động nếu bạn đang sử dụng một phiên bản cũ hơn). Nó đi một cái gì đó như:

AllDevicesController.all_devices.sort_by { |e| e.nil? ? 0 : e[4] } 

này sẽ đối xử với phụ mảng với không có yếu tố thứ 4 như thể nó là 0. Thay đổi liên tục này để phù hợp với bạn.

EDIT:

Sau khi bạn điều chỉnh đầu vào, nó bây giờ đã rõ ràng bạn đã tiến rất gần đến câu trả lời đúng. Mã của bạn cần phải có được:

AllDevicesController.all_devices.sort do |a, b| 
    a[4] <=> b[4] 
end 

Hoặc đơn giản (giả sử của Ruby 1.8.7 trở lên):

AllDevicesController.all_devices.sort_by { |e| e[4] } 

Trong cả hai trường hợp, các biến ab sẽ chứa các thành phần của mảng ban đầu, điều này là lý do tại sao bạn có thể truy cập trực tiếp vào một phần tử ở bất kỳ vị trí nào (và bạn không cần một cái gì đó như a[][4], đó là cú pháp Ruby không chính xác).

+0

Tôi, tất nhiên, bỏ phần tử thứ 4 của phần tử thứ 0 của device_array. Không nên có bất kỳ đối tượng nil. –

+0

Trong trường hợp đó, vấn đề duy nhất của bạn là sử dụng 'a [] [4]' thay vì 'a [4]'. 'a [] [4]' không phải là cú pháp Ruby hợp lệ. –

2

Yếu tố thứ 4 là thực tại chỉ số 3, có nghĩa là bạn sẽ làm điều đó như thế này:

all_devices.sort do |a, b| 
    a[3] <=> b[3] 
end 

Nếu bạn thực sự muốn sắp xếp các yếu tố ở chỉ số 4 (mà không tồn tại cho phần tử đầu tiên của all_devices), sau đó bạn cần phải thêm so với NilClass đầu tiên:

class NilClass 
    def <=> (other) 
    1 
    end 
end 

all_devices.sort do |a, b| 
    a[4] <=> b[4] 
end 

này sẽ sắp xếp nil đến cùng.Thay đổi giá trị trả về của <=> thành -1 để sắp xếp chúng về phía trước.

+0

Phương pháp này có thể khiến lỗi bắt gặp khó khăn hơn một chút; vì nó sẽ cho phép so sánh với 'nil' ở mọi nơi trong mã. Nó nên được sử dụng một cách khôn ngoan. –

2

Tôi biết các câu hỏi đã được trả lời, và tôi sẽ không giải quyết nó bây giờ, nhưng ..

Bạn có chắc chắn một mảng sẽ là phù hợp nhất cho dữ liệu đó? Tôi đang nói về các yếu tố dữ liệu này: ["name1", "type1", ["A", "N", "N"], ["Thuộc tính", "device_attribute"], 9]

Có vẻ như một Struct hoặc một cái gì đó có thể phù hợp hơn và quản lý được cho điều này, và sau đó bạn có thể có một loạt các Structs. Chỉ là một ý tưởng.

Các vấn đề liên quan