2009-07-28 21 views
19

Ho un array di array in questo modo:Ordinamento di un array di array in 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]] 

desidero ordinare l'intero device_array al 4 ° elemento.

Ho provato

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 

Ho anche provato:

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

Entrambi i metodi non hanno funzionato.

Io sto usando questo come un punto di riferimento: http://ariejan.net/2007/01/28/ruby-sort-an-array-of-objects-by-an-attribute/

immagino che mi manca qualcosa rubyish che rende il tutto veramente facile.

risposta

22

Non è possibile utilizzare <=> con nil.

Il codice dovrebbe essere qualcosa di simile:

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

Questo metterà i sub-array che non hanno alcun elemento di indice di 4 all'inizio del risultato. Per farlo viceversa, scambia -1 con 1.

È inoltre possibile utilizzare sort_by anziché sort. Penso che questo sia stato introdotto in Ruby 1.8.7 (quindi potrebbe non funzionare se si sta utilizzando una versione precedente). Va qualcosa come:

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

Ciò trattare sotto-array senza 4 ° elemento come se fosse 0. Cambiare questa costante le proprie esigenze.

EDIT:

Dopo aver regolato l'ingresso, è ormai chiaro che eri molto vicino alla risposta giusta. Il codice dovrebbe essere:

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

o Semplice (supponendo di Ruby 1.8.7 o più):

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

In entrambi i casi, le variabili a e b conterrà elementi della matrice originale, questo è il motivo per cui puoi accedere direttamente a un elemento in qualsiasi posizione (e non hai bisogno di qualcosa come a[][4], che è sintassi Ruby errata).

+0

Io, ovviamente, ho omesso il quarto elemento dello 0 ° elemento del array_apparecchio. Non dovrebbero esserci oggetti nulli. –

+0

In questo caso il tuo unico problema è usare 'a [] [4]' invece di 'a [4]'. 'a [] [4]' non è valido Sintassi di Ruby. –

2

Il quarto elemento è in realtà in corrispondenza dell'indice 3, il che significa che si dovrebbe fare in questo modo:

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

Se davvero si vuole ordinare gli elementi a indice 4 (che non esiste per il primo elemento di all_devices), allora è necessario aggiungere rispetto alla prima NilClass:

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

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

Ciò ordinerà nil fino alla fine.Modificare il valore restituito da <=> a -1 per ordinarli in primo piano.

+0

Questo metodo può finire a rendere gli errori di cattura un po 'più difficili; in quanto consentirebbe il confronto con 'nil' ovunque nel codice. Dovrebbe essere usato con saggezza. –

2

So che la questione è stata risolta, e non ho intenzione di affrontare ora, ma ..

Sei sicuro di una matrice sarebbe la soluzione migliore per quei dati? Sto parlando di questi elementi di dati: [ "nome1", "tipo1", [ "A", "N", "N"], [ "attributo", "device_attribute"], 9]

Sembra un Struct o qualcosa potrebbe essere più appropriato e gestibile per questo, e quindi si può avere una serie di strutture. Solo un'idea

Problemi correlati