2012-06-08 9 views
5

Sagen, ich habe einen Hash wie:Sortieren Hash durch die Länge der enthaltenen Werte

foo = { 
    :bar => ['r', 'baz'], # has a total str length of 4 characters inside of the array 
    :baz => ['words', 'etc', 'long words'] # has a total str length of 18 characters inside of the array, 
    :blah => ['at'] # has a total str length of 2 characters inside of the array 
    # etc... 
} 

Wie würde ich durch die gesamte Zeichenfolge gehen über Länge der Elemente innerhalb der Arrays enthalten diese Hash-Sortierung? Die resultierende Hash-Ordnung in diesem Fall sollte sein: :blah, :bar, :baz

+1

Was meinen Sie mit "Sortieren von Hash"? – nonowarn

+2

Stell dir vor, Ruby kann dir nicht helfen. Was würdest du dann tun? – alf

+0

@alf Ich schätze, ich wäre SOL ... aber wie hilft es mir das zu zeigen? –

Antwort

11

Ich würde dies nur tun:

Hash[foo.sort_by { |k, v| v.join.length }] 

Ich nehme an, Sie sind nicht die Werte ändern die ursprünglichen Hash zu wollen, gerade wieder um sie.

1
foo.sort_by { |_,v| v.reduce(:+).size } 
+0

Sogar 'reduce (: +)' ist genug. Allerdings sortiert dies nach Zeichenketten (alphabetisch), nicht nach Zeichenkettenlänge. – Casper

+0

@Casper du hast Recht. Ich habe die Antwort bearbeitet, um die Stringlänge zu verwenden. –

3

Traditionell Hashes sind nicht geordnet, und daher nicht sortierbar. Ruby 1.9-Hashes sind geordnet, aber die Sprache bietet keine einfache Möglichkeit, die Elemente neu zu ordnen. Genau wie in 1.8, ein Hash-Sortierung gibt ein Array von Paaren: (. Eigentlich 1.8 auf, dass die Luft sprengen würde, weil Symbole in 1.8 nicht vergleichbar sind, aber egal)

{ c:3, a:1, b:2 }.sort => [ [:a,1], [:b,2], [:c,3] ] 

Aber als Solange Sie mit der Liste der Paare einverstanden sind, können Sie einen Hash (oder ein Array) nach beliebigen Kriterien sortieren. Verwenden Sie einfach sort_by und einen Block übergeben, die den Sortierschlüssel extrahiert, oder verwenden Sie Art mit einem Block, der den Vergleich macht:

foo.sort_by { |key, strings| strings.join.length } 

oder, wenn Sie die längsten wollen zuerst:

foo.sort_by { |key, strings| -strings.join.length } 

Dann wenn Sie mit 1,9 und wollen das Ergebnis wieder in einem Hash drehen, können Sie dies so tun (danke, Jörg W Mittag):

Hash[ foo.sort_by { |key, strings| strings.join.length } ] 

..., die die gleiche Antwort wie d11wtq ist.

+0

'Hash :: []' nimmt genau die Art von Schlüssel-Wert-Arrays, die alle anderen 'Hash'-Methoden erzeugen, also, wenn Sie' '' '' '' '' '' '' '' '' Hash '' '' '' ' Wickeln Sie einfach den gesamten Ausdruck in 'Hash [...]', um einen 'Hash' zurück zu bekommen. –

1

Hash nicht die Reihenfolge der Schlüssel in seinem Konzept. Aber in Ruby 1.9, Hash's key order is saved. Sie können Code in anderen Antworten verwenden, wenn Sie 1.9 verwenden.

Aber ich möchte nicht empfehlen, dieses Verhalten zu verlassen, weil es implizites Verhalten ist und ich vor zukünftigen Änderungen Angst habe. Verwenden Sie stattdessen die Methode, die den Hash-Eintrag in der Reihenfolge der Länge der Strings ergibt.

def each_by_length(hash) 
    hash = hash.sort_by { |_, strs| strs.map(&:length).inject(0, &:+) } 
    hash.each do |k, v| 
    yield k, v 
    end 
end 
Verwandte Themen