it-swarm.com.de

Sortieren Sie den Hash nach Schlüssel, geben Sie den Hash in Ruby

Wäre dies der beste Weg, um einen Hash zu sortieren und ein Hash-Objekt zurückzugeben (anstelle von 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

In Ruby 2.1 ist es einfach:

h.sort.to_h
204
Mark Thomas

Hinweis: Ruby> = 1.9.2 hat einen auftragserhaltenden Hash: Die eingefügten Auftragsschlüssel werden in der Reihenfolge aufgelistet, in der sie aufgeführt sind. Das Folgende gilt für ältere Versionen oder für abwärtskompatiblen Code.

Es gibt kein Konzept für einen sortierten Hash. Also nein, was du tust ist nicht richtig.

Wenn Sie möchten, dass es zur Anzeige sortiert wird, geben Sie eine Zeichenfolge zurück:

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

oder, falls Sie die Schlüssel in der richtigen Reihenfolge haben möchten:

h.keys.sort

oder, wenn Sie auf die Elemente in der angegebenen Reihenfolge zugreifen möchten:

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

zusammenfassend ist es jedoch nicht sinnvoll, von einem sortierten Hash zu sprechen. Aus docs , "Die Reihenfolge, in der Sie einen Hash entweder mit einem Schlüssel oder mit einem Wert durchlaufen, mag willkürlich erscheinen und wird im Allgemeinen nicht in der Einfügereihenfolge sein." Das Einfügen von Schlüsseln in einer bestimmten Reihenfolge in den Hash wird also nicht helfen.

80
Peter

Ich habe immer sort_by Verwendet. Sie müssen die Ausgabe #sort_by Mit Hash[] Umbrechen, damit ein Hash ausgegeben wird, andernfalls wird ein Array von Arrays ausgegeben. Um dies zu erreichen, können Sie alternativ die Methode #to_h Für das Array von Tupeln ausführen, um sie in eine k=>v - Struktur (Hash) zu konvertieren.

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

Es gibt eine ähnliche Frage in " Wie wird ein Ruby Hash nach Zahlenwert sortiert? ".

63
boulder_ruby

Nein, das ist es nicht (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)

Bei großen Hashes steigt die Differenz auf das 10-fache und mehr

13
fl00r

Du hast dir im OP die beste Antwort gegeben: Hash[h.sort] Wenn Sie sich nach mehr Möglichkeiten sehnen, finden Sie hier eine direkte Änderung des ursprünglichen Hashs, um ihn zu sortieren:

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

ActiveSupport :: OrderedHash ist eine weitere Option, wenn Sie Ruby 1.9.2 nicht verwenden oder Ihre eigenen Problemumgehungen ausführen möchten.

6
eremite

Sortieren Sie den Hash nach Schlüssel, geben Sie den Hash in Ruby zurück

Mit destructuring und Hash # sort

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

Enumerable # sort_by

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

Hash # Sortierung mit Standardverhalten

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 }

Hinweis: <Ruby 2.1

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

Hinweis:> Ruby 2.1

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

Ich hatte das gleiche Problem (ich musste meine Geräte nach ihrem Namen sortieren) und ich löste es folgendermaßen:

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

@equipments ist ein Hash, den ich auf meinem Modell aufbaue und auf meinem Controller zurückgebe. Wenn Sie .sort aufrufen, wird der Hash basierend auf seinem Schlüsselwert sortiert.

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