web-dev-qa-db-fra.com

Trier le hachage par clé, retourner le hachage dans Ruby

Serait-ce le meilleur moyen de trier un hachage et de renvoyer un objet Hash (au lieu de Array):

h = {"a"=>1, "c"=>3, "b"=>2, "d"=>4}
# => {"a"=>1, "c"=>3, "b"=>2, "d"=>4}

Hash[h.sort]
# => {"a"=>1, "b"=>2, "c"=>3, "d"=>4}
247
Vincent

En Ruby 2.1, c'est simple:

h.sort.to_h
204
Mark Thomas

Remarque: Ruby> = 1.9.2 a un hachage préservant l'ordre: les clés d'ordre insérées correspondent à l'ordre dans lequel elles sont énumérées. Ce qui suit s’applique aux anciennes versions ou aux codes rétrocompatibles.

Il n'y a pas de concept de hachage trié. Donc non, ce que vous faites n'est pas juste.

Si vous voulez qu'il soit trié pour l'affichage, retournez une chaîne:

"{" + h.sort.map{|k,v| "#{k.inspect}=>#{v.inspect}"}.join(", ") + "}"

ou, si vous voulez les clés dans l’ordre:

h.keys.sort

ou, si vous souhaitez accéder aux éléments dans l'ordre:

h.sort.map do |key,value|
  # keys will arrive in order to this block, with their associated value.
end

mais en résumé, cela n'a aucun sens de parler d'un hachage trié. Dans docs , "L’ordre dans lequel vous parcourez un hachage avec une clé ou une valeur peut sembler arbitraire et ne sera généralement pas dans l’ordre d’insertion." Donc, insérer des clés dans un ordre spécifique dans le hachage ne vous aidera pas.

80
Peter

J'ai toujours utilisé sort_by. Vous devez encapsuler la sortie #sort_by avec Hash[] pour lui faire afficher un hachage, sinon elle génère un tableau de tableaux. Pour ce faire, vous pouvez également exécuter la méthode #to_h sur le tableau de tuples afin de les convertir en une structure k=>v (hachage).

hsh ={"a" => 1000, "b" => 10, "c" => 200000}
Hash[hsh.sort_by{|k,v| v}] #or hsh.sort_by{|k,v| v}.to_h

Il existe une question similaire dans " Comment trier un Ruby Hash par valeur numérique? ".

63
boulder_ruby

Non, ce n'est pas (Ruby 1.9.x)

require 'benchmark'

h = {"a"=>1, "c"=>3, "b"=>2, "d"=>4}
many = 100_000

Benchmark.bm do |b|
  GC.start

  b.report("hash sort") do
    many.times do
      Hash[h.sort]
    end
  end

  GC.start

  b.report("keys sort") do
    many.times do
      nh = {}
      h.keys.sort.each do |k|
        nh[k] = h[k]
      end
    end
  end
end

       user     system      total        real
hash sort  0.400000   0.000000   0.400000 (  0.405588)
keys sort  0.250000   0.010000   0.260000 (  0.260303)

Pour les grands hachages, la différence passera à 10x et plus

13
fl00r

Vous vous êtes donné la meilleure réponse dans l'OP: Hash[h.sort] Si vous avez envie de plus de possibilités, voici une modification en place du hachage d'origine pour le trier:

h.keys.sort.each { |k| h[k] = h.delete k }
12
Boris Stitnicky

ActiveSupport :: OrderedHash est une autre option si vous ne souhaitez pas utiliser Ruby 1.9.2 ou lancer vos propres solutions de contournement.

6
eremite

Trier le hachage par clé, retourner le hachage en Ruby

Avec déstructuration et tri par hachage

hash.sort { |(ak, _), (bk, _)| ak <=> bk }.to_h

Enumérable # sort_by

hash.sort_by { |k, v| k }.to_h

Hash # sort avec un comportement par défaut

h = { "b" => 2, "c" => 1, "a" => 3  }
h.sort         # e.g. ["a", 20] <=> ["b", 30]
hash.sort.to_h #=> { "a" => 3, "b" => 2, "c" => 1 }

Remarque: <Ruby 2.1

array = [["key", "value"]] 
hash  = Hash[array]
hash #=> {"key"=>"value"}

Remarque:> Ruby 2.1

[["key", "value"]].to_h #=> {"key"=>"value"}
4
Moriarty

J'ai eu le même problème (je devais trier mes équipements par leur nom) et j'ai résolu comme ça:

<% @equipments.sort.each do |name, quantity| %>
...
<% end %>

@equipments est un hash que je construis sur mon modèle et que je retourne sur mon contrôleur. Si vous appelez .sort, le hachage sera trié en fonction de sa valeur clé.

0
Gabriel Mesquita
@ordered = {}
@unordered.keys.sort.each do |key|
  @ordered[key] = @unordered[key]
end
0
beornborn