Comment trier un Ruby Hash par valeur numérique?

154

J'ai un hachage de compteur que j'essaie de trier par décompte. Le problème que je rencontre est que la fonction par défaut Hash.sort trie les nombres comme des chaînes plutôt que par taille de nombre.

ie Donné Hash:

metrics = {"sitea.com" => 745, "siteb.com" => 9, "sitec.com" => 10 }

Exécution de ce code:

metrics.sort {|a1,a2| a2[1]<=>a1[1]}

renverra un tableau trié:

[ 'siteb.com', 9, 'sitea.com', 745, 'sitec.com', 10]

Même si 745 est un nombre supérieur à 9, 9 apparaîtra en premier dans la liste. En essayant de montrer qui a le plus grand nombre, cela me rend la vie difficile. :)

Des idées sur la façon de trier un hachage (ou même un tableau) par taille de valeur numérique?

J'apprécie toute aide.

Dustin M.
la source
quelle version ruby ​​utilisez-vous? votre résultat de tri est très étrange
fl00r

Réponses:

268

Aucune idée de la façon dont vous avez obtenu vos résultats, car il ne trierait pas par valeur de chaîne ... Vous devriez inverser a1et a2dans votre exemple

Le meilleur moyen dans tous les cas (selon Mladen) est:

metrics = {"sitea.com" => 745, "siteb.com" => 9, "sitec.com" => 10 }
metrics.sort_by {|_key, value| value}
  # ==> [["siteb.com", 9], ["sitec.com", 10], ["sitea.com", 745]]

Si vous avez besoin d'un hachage, vous pouvez utiliser to_h(dans Ruby 2.0+)

metrics.sort_by {|_key, value| value}.to_h
  # ==> {"siteb.com" => 9, "sitec.com" => 10, "sitea.com", 745}
Marc-André Lafortune
la source
84
ou simplementsort_by{|k,v| v}
Mladen Jablanović
Mon numéro revenait sous forme de chaîne, cela a corrigé le problème .. J'avais a2 et a1 dans cet ordre parce que je voulais que les résultats soient triés par ordre décroissant .. merci pour vos commentaires.
Dustin M.
c'est pourquoi j'aime Ruby ... un tel problème est la douleur dans la tête dans d'autres langues. so simple
Hady Elsahar
18
@Elchin: vous pouvez utilisermetrics.sort_by{ |k, v| v }.reverse.to_h
Marc-André Lafortune
4
En fait encore plus simple que: hash.sort_by (&: last) avec la même mise en garde concernant l'obtention d'un tableau de paires par rapport à un hachage.
Gerry Gleason
84

Puisque la valeur est la dernière entrée, vous pouvez faire:

metrics.sort_by(&:last)
shock_one
la source
4
C'est génial! toute référence pour la pré-définition de &:last?
Tamer Shlash
sort_by(&:last)est en fait un raccourci pour sort_by {|x| x.last} stackoverflow.com/questions/1217088/…
Beni Cherniavsky-Paskin
14

Déjà répondu mais toujours. Changez votre code en:

metrics.sort {|a1,a2| a2[1].to_i <=> a1[1].to_i }

Converti en chaînes en cours de route ou non, cela fera l'affaire.

dimitarvp
la source
9

Ce n'est pas le comportement que je vois:

irb(main):001:0> metrics = {"sitea.com" => 745, "siteb.com" => 9, "sitec.com" =>
 10 }
=> {"siteb.com"=>9, "sitec.com"=>10, "sitea.com"=>745}
irb(main):002:0> metrics.sort {|a1,a2| a2[1]<=>a1[1]}
=> [["sitea.com", 745], ["sitec.com", 10], ["siteb.com", 9]]

Est-il possible que quelque part le long de la ligne, vos nombres soient convertis en chaînes? Y a-t-il plus de code que vous ne publiez pas?

Jacob Mattison
la source
Ahh votre droite, il semble que le résultat dans mon code le renvoie sous forme de chaîne. Types de données inquiétants. :) Parfois, je suis trop près du problème. Merci.
Dustin M.
1
Ouaip. Parfois, j'entends quelqu'un qualifier Ruby de "non typé". Oh, non, c'est définitivement tapé. Ce n'est tout simplement pas typé statiquement. :)
Jacob Mattison