2009-07-28 12 views
19

J'ai un tableau de tableaux comme ceci:Tri d'un tableau de tableaux en 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]] 

Je voudrais trier l'ensemble device_array sur le 4ème élément.

J'ai essayé

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 

J'ai aussi essayé:

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

Les deux méthodes ont pas fonctionné.

j'utilisais comme référence: http://ariejan.net/2007/01/28/ruby-sort-an-array-of-objects-by-an-attribute/

J'imagine que je suis absent rubyish quelque chose qui fait vraiment facilement.

Répondre

22

Vous ne pouvez pas utiliser <=> avec nil.

Votre code devrait être quelque chose comme ceci:

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

Cela mettra les sous-réseaux qui ont aucun élément d'indice 4 au début du résultat. Pour le faire dans l'autre sens, permutez -1 avec 1. Vous pouvez également utiliser sort_by au lieu de sort. Je pense que cela a été introduit dans Ruby 1.8.7 (donc cela pourrait ne pas fonctionner si vous utilisez une version plus ancienne). Il va quelque chose comme:

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

Cela traitera des sous-réseaux sans élément 4 comme si elle était 0. Pour changer cette constante qui vous convient.

EDIT:

Après avoir ajusté l'entrée, il est maintenant clair que vous étiez très proche de la bonne réponse. Votre code aurait dû être:

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

Ou simple (en supposant que Ruby 1.8.7 ou plus):

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

Dans les deux cas, les variables a et b contiendra des éléments du tableau d'origine, cette C'est pourquoi vous pouvez accéder directement à un élément dans n'importe quelle position (et vous n'avez pas besoin de quelque chose comme a[][4], ce qui est une syntaxe Ruby incorrecte).

+0

J'ai, bien sûr, omis le 4ème élément du 0ème élément du device_array. Il ne devrait pas y avoir d'objets nuls. –

+0

Dans ce cas, votre seul problème est d'utiliser 'a [] [4]' au lieu de 'a [4]'. 'a [] [4]' n'est pas une syntaxe Ruby valide. –

2

Le 4ème élément est en fait à l'index 3, ce qui signifie que vous le feriez comme ceci:

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

Si vous voulez vraiment trier les éléments à l'index 4 (qui n'existe pas pour le premier élément de all_devices), alors vous devez ajouter à la comparaison NilClass premier:

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

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

Cette triera nil à la fin.Modifiez la valeur de retour de <=> à -1 pour les trier vers l'avant.

+0

Cette méthode peut finir par rendre les bogues plus difficiles à attraper; car cela permettrait une comparaison avec «nul» partout dans le code. Il devrait être utilisé à bon escient. –

2

Je le sais, a répondu à la question, et je ne vais pas répondre maintenant, mais ..

Etes-vous sûr un tableau serait la meilleure solution pour ces données? Je parle de ces éléments de données: ["nom1", "type1", ["A", "N", "N"], ["Attribut", "device_attribute"], 9]

un Struct ou quelque chose pourrait être plus approprié et gérable pour cela, et alors vous pouvez avoir un tableau de structures. Juste une idée.

Questions connexes