2009-07-28 14 views
19

Ich habe ein Array von Arrays wie folgt:Sortierung ein Array von Arrays 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]] 

Ich mag würde die gesamte device_array am 4. Elemente sortieren.

Ich habe versucht,

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 

ich auch versucht habe:

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

Beide Methoden nicht gearbeitet haben.

Ich war mit dieser als Referenz: http://ariejan.net/2007/01/28/ruby-sort-an-array-of-objects-by-an-attribute/

Ich stelle ich mir etwas rubyish fehlt bin, dass dies wirklich einfach macht.

Antwort

22

Sie können <=> mit nil nicht verwenden.

Ihr Code soll wie folgt sein:

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

Dadurch wird die Unterfelder setzen, die kein Element des Index 4 zu Beginn des Ergebnisses haben. Um es umgekehrt zu machen, tauschen Sie -1 mit 1.

Sie könnten auch sort_by anstelle von sort verwenden. Ich denke, dies wurde in Ruby 1.8.7 eingeführt (es funktioniert möglicherweise nicht, wenn Sie eine ältere Version verwenden). Es geht ungefähr so:

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

Dies wird ohne vierte Element Subanordnungen zu behandeln, als ob es 0 Veränderung war diese Konstante zu Ihnen passt.

EDIT:

Nachdem Sie die Eingabe eingestellt, ist es nun klar ist, dass Sie auf die richtige Antwort sehr nahe waren. Der Code sollte gewesen sein:

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

Oder einfach (vorausgesetzt, Ruby-1.8.7 oder mehr):

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

In beiden Fällen die Variablen a und b werden Elemente des ursprünglichen Arrays enthalten, diese Deshalb können Sie direkt auf ein Element in jeder Position zugreifen (und Sie benötigen nicht etwa a[][4], was eine falsche Ruby-Syntax ist).

+0

Ich natürlich das vierte Element des 0. Elements des Device_array weggelassen. Es sollte keine Nullobjekte geben. –

+0

In diesem Fall ist Ihr einziges Problem die Verwendung von 'a [] [4]' anstelle von 'a [4]'. 'a [] [4]' ist keine gültige Ruby-Syntax. –

2

Das vierte Element ist eigentlich bei Index 3, was bedeutet, dass Sie es so tun würde:

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

Wenn Sie wirklich die Elemente an der Stelle 4 sortieren möchten (was nicht für das erste Element nicht vorhanden ist von all_devices), dann müssen Sie Vergleich zum NilClass zuerst hinzuzufügen:

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

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

Diese nil wird sortieren bis zum Ende.Ändern Sie den Rückgabewert von <=> in -1, um sie nach vorne zu sortieren.

+0

Diese Methode kann dazu führen, dass die Fehlersuche etwas schwieriger wird; weil es einen Vergleich mit "Null" überall im Code ermöglichen würde. Es sollte mit Bedacht verwendet werden. –

2

weiß, dass ich die Frage beantwortet wurde, und ich bin es jetzt nicht gehen zu adressieren, aber ..

Sind Sie sicher, dass ein Array die beste Lösung für diese Daten sein würde? Ich spreche über diese Datenelemente: ["Name1", "Typ1", ["A", "N", "N"], ["Attribut", "Geräteattribut"], 9]

Scheint wie a Struct oder etwas könnte dafür geeigneter und handhabbarer sein, und dann können Sie eine Reihe von Structs haben. Nur eine Idee.