2012-06-08 18 views
5

Say mam hash jak:Sortuj według długości hash zawartych wartości

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... 
} 

Jak bym go o sortowaniu to skrót od całkowitej długości łańcucha z elementów zawartych w macierzy? Powstały kolejność mieszania w tym przypadku powinno być: :blah, :bar, :baz

+1

Co masz na myśli przez "sortowanie hash"? – nonowarn

+2

Wyobraź sobie przez sekundę Ruby nie może ci pomóc. Co byś wtedy zrobił? – alf

+0

@ Chyba bym był SOL ... ale jak mi to pomaga? –

Odpowiedz

11

ja po prostu to zrobić:

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

Zakładam, że nie jesteś zamierzający zmianę pierwotnych wartości mieszania, po prostu ponownie zamówić je.

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

Nawet 'reduce (: +)' wystarczy. Jednak sortuje według ciągu (alfabetycznie), a nie według długości łańcucha. – Casper

+0

@Casper masz rację. Edytowałem odpowiedź, aby użyć długości ciągu znaków. –

3

Tradycyjnie skróty nie są uporządkowane, a zatem nie sortable. Pakiety języka Ruby 1.9 są uporządkowane, ale język nie zapewnia prostego sposobu na ponowne zamówienie elementów. Podobnie jak w 1.8, sortowania mieszania zwraca tablicę par: (. Faktycznie, 1,8 byłoby wysadzić na tym, ponieważ symbole nie są porównywalne w 1,8, ale nic nie szkodzi)

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

ale jako o ile jesteś w porządku z listą par, możesz posortować hash (lub tablicę) według własnych upodobań. Wystarczy użyć sort_by i przekazać blok, który wydobywa klucz sortowania lub użyj sort z bloku, który robi porównania:

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

lub, jeśli chcesz najdłuższych pierwszy:

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

Następnie jeśli używasz 1.9 i chcą przekręcić wynik z powrotem do Hash, można to zrobić w ten sposób (dzięki, Jörg w Mittag):

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

... która jest taka sama odpowiedź jak d11wtq.

+0

'Hash :: []' bierze dokładnie taki rodzaj tablic wartości klucz-wartość, że wszystkie inne metody 'Hash' dają, więc jeśli chcesz' map' lub 'sort' lub' sort_by' a 'Hash', ty po prostu zawiń całe wyrażenie w 'Hash [...]', aby odzyskać 'Hash'. –

1

Hash nie zapewnia kolejności kluczy w swojej koncepcji. Ale w Rubim 1.9, Hash's key order is saved. Więc możesz użyć kodu w innych odpowiedziach, jeśli używasz 1.9.

Ale nie chcę zalecać, aby polegać na tym zachowaniu, ponieważ jest to zachowanie niejawne i obawiam się przyszłych zmian. Zamiast tego użyj metody, która daje hash w porządku sumy długości łańcuchów.

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 
Powiązane problemy