web-dev-qa-db-fra.com

Comment trier un hachage Ruby par ordre alphabétique

J'essaie de trier un hachage alphabétiquement par clé, mais je n'arrive pas à trouver le moyen de le faire sans créer ma propre classe de tri. J'ai trouvé le code ci-dessous pour trier par valeur s'il s'agit d'un entier et j'essaie de le modifier sans avoir de chance. 

temp["ninjas"]=36
temp["pirates"]=12
temp["cheese"]=222
temp.sort_by { |key, val| key }

Mon objectif est de classer le hachage par clé, puis de générer les valeurs. Je devrai le faire plusieurs fois avec différents ordres de hachage mais avec les mêmes valeurs.

16
Rilcon42

En supposant que vous souhaitiez que la sortie soit un hachage qui parcourt les clés dans un ordre trié, vous y êtes presque. Hash#sort_by renvoie une Array de Arrays, et les tableaux internes sont tous deux des éléments.

La variable Hash de Ruby a un constructeur qui peut utiliser cette sortie. 

Essaye ça:

temp = Hash[ temp.sort_by { |key, val| key } ]

ou plus concise

temp = temp.sort_by { |key| key }.to_h

Si votre hachage contient plusieurs types de clé, cela ne fonctionnera pas (par exemple, Ruby ne triera pas automatiquement entre Strings et Symbols) et vous obtiendrez un message d'erreur du type Comparison de Symbol avec String (ArgumentError). Si oui, vous pouvez modifier ce qui précède pour 

temp = Hash[ temp.sort_by { |key, val| key.to_s } ] 

pour contourner le problème. Soyez toutefois averti que les clés conserveront leurs types d'origine, ce qui pourrait poser des problèmes avec des hypothèses dans le code ultérieur. En outre, la plupart des classes intégrées prennent en charge une méthode .to_s; vous pouvez donc en obtenir des résultats indésirables (tels qu'un ordre de tri inattendu pour les clés numériques ou d'autres types inattendus).

Vous pouvez, en plus, convertir les clés en Strings avec quelque chose comme ceci:

temp = Hash[ temp.map { |key, val| [key.to_s, val] }.sort ] 

. . . bien que cette approche permette de perdre des informations sur le type de la clé d'origine, rendant impossible le renvoi fiable aux données d'origine.

26
Neil Slater
sorted_by_key = Hash[original_hash.sort]

créera un nouveau hachage en insérant la clé/les valeurs de original_hash alphabétiquement par clé. Les hachages Ruby 2.x mémorisent leur ordre d'insertion. Ce nouveau hachage apparaîtra donc trié par clé si vous l'énumérez ou le sortez.

Si vous insérez plus d'éléments dans un ordre non alphabétique, cela ne tiendra évidemment pas.

En outre, cela suppose que les clés de hachage d'origine sont toutes triables/comparables.

7
sickp

Ruby's Hash se souvient de son ordre d'insertion maintenant, mais pas auparavant Rubies <v1.9. Mais, ne vous occupez pas de trier un hachage car il n’ya aucun avantage à le faire, car au fond un hachage est une structure à accès aléatoire. Cela signifie que tous les éléments sont accessibles à tout moment et que vous soyez le premier ou le dernier n'a pas d'importance, vous pouvez y accéder de la même manière. 

Cela ne ressemble pas à un tableau qui agit comme un fichier texte séquentiel, une chaîne ou une file d'attente et vous devez y accéder de manière linéaire en itérant dessus, ce qui, à ce stade, l'ordre des éléments fait une grande différence.

Ainsi, avec un hachage, récupérez les clés, triez-les et faites une itération sur la liste des clés ou utilisez values_at pour extraire toutes les valeurs simultanément. Par exemple:

hash = {
    'z' => 9,
    'a' => 1
}

sorted_keys = hash.keys.sort # => ["a", "z"]
sorted_keys.each do |k|
  puts hash[k]
end
# >> 1
# >> 9

hash.values_at(*sorted_keys) # => [1, 9]

Certaines langues ne vous permettent même pas de trier le hachage, et y accéder via une liste de clés triée est le seul moyen d'extraire les éléments dans un ordre. Il est donc probablement préférable de ne pas prendre l'habitude de compter les paires clé/valeur et utilisez plutôt les clés.

4
the Tin Man

Vous pouvez créer un nouveau hachage vide pour contenir les données de hachage triées. Parcourez le tableau retourné et chargez les données dans le nouveau hachage pour contenir les données de hachage triées. 

temp = {}
temp["ninjas"]=36
temp["pirates"]=12
temp["cheese"]=222 
temp = temp.sort_by { |key, val| key }

temp_sorted = {}
temp.each { |sub_arr| temp_sorted[sub_arr[0]] = sub_arr[1] } 
temp = temp_sorted

temp est maintenant égal à {"cheese" => 222, "ninjas" => 36, "pirates" => 12}

0
Jake