Как отсортировать не простой хеш (hash of hashes)

У меня есть хэш как это

{ 55 => {:value=>61, :rating=>-147},
  89 => {:value=>72, :rating=>-175},
  78 => {:value=>64, :rating=>-155},
  84 => {:value=>90, :rating=>-220},
  95 => {:value=>39, :rating=>-92},
  46 => {:value=>97, :rating=>-237},
  52 => {:value=>73, :rating=>-177},
  64 => {:value=>69, :rating=>-167},
  86 => {:value=>68, :rating=>-165},
  53 => {:value=>20, :rating=>-45}
}

Как я могу отсортировать по : рейтингу ? Или, может быть, я должен использовать другую структуру?

12.12.2008 07:23:37
Наверное, стоит отметить язык программирования в названии.
danieltalsky 12.12.2008 07:46:34
3 ОТВЕТА
РЕШЕНИЕ

Я бы изменил структуру данных на массив хешей:

my_array =
[
  {:id => 78, :value=>64, :rating=>-155},
  {:id => 84, :value=>90, :rating=>-220},
  {:id => 95, :value=>39, :rating=>-92}
]

Вы можете легко отсортировать такую ​​структуру с

my_array.sort_by { |record| record[:rating] }

Чтобы получить хеш-подобную функцию извлечения записи по id, вы можете определить новый метод в my_array:

def my_array.find_by_id(id) 
  self.find { |hash| hash[:id] == id }
end

так что после этого вы можете сделать

my_array.find_by_id(id)

вместо

my_hash[id]
6
13.12.2008 12:53:48
Не уверен, что ответ на этот комментарий будет получен через 4 года .... Причина, по которой я использую хеш, состоит в том, чтобы использовать ключ, к которому я могу напрямую обращаться и увеличивать значения, например, h [436246]. После того, как я заполнил хеш, я должен преобразовать в массив
nilanjan 4.01.2013 14:39:33
Вы можете снова преобразовать его в Hash с помощью Hash[my_array.sort_by { |record| record[:rating] }]. При использовании Ruby 1.9.x или более поздней версии, поскольку он поддерживает порядок сортировки хеша внутри.
Morgan Christiansson 20.01.2013 16:36:32
Спасибо, это взломало это для меня. Намного приятнее работать со структурой данных! ..... хотя этот пост такой старый, я кое-чему научился :)
Tyrone Wilson 15.04.2013 19:29:34

Хэши в Ruby не могут быть отсортированы (по крайней мере, до 1.9)

Это означает, что цикл через Hash не обязательно даст информацию в правильном порядке для вас. Тем не менее, легко зацикливаться на хэшированных данных в определенном порядке, сначала преобразовав их в массив, и фактически вызов методов сортировки в хэше преобразует их в массив для вас:

>> { :a => 4, :b => 12, :c => 3, :d => 8 }.sort_by { |key, value| value }
=> [[:c, 3], [:a, 4], [:d, 8], [:b, 12]]

Итак, в вашем случае:

hsh.sort_by {|key, ratings| ratings[:rating] }
5
13.12.2008 09:52:43
@Gaius - спасибо за редактирование, но код работает как написано. Весь мой смысл был в том, что #sort_by неявно выполняет преобразование Array без необходимости вставлять .to_a - даже в Ruby 1.8
Gareth 13.12.2008 09:55:47

Возможно, существует лучшая структура данных, но (я предполагаю, что это ruby), это можно сделать в Ruby, используя встроенный стиль сортировки, чтобы в основном рассказать, как сравнивать два. Вот конкретный пример:

my_hash = { 
  55 => {:value=>61, :rating=>-147},
  89 => {:value=>72, :rating=>-175},
  78 => {:value=>64, :rating=>-155},
  84 => {:value=>90, :rating=>-220},
  95 => {:value=>39, :rating=>-92},
  46 => {:value=>97, :rating=>-237},
  52 => {:value=>73, :rating=>-177},
  64 => {:value=>69, :rating=>-167},
  86 => {:value=>68, :rating=>-165},
  53 => {:value=>20, :rating=>-45}
}

puts "MY HASH"
my_hash.each do |local|
  puts local
end

sorted_hash = my_hash.sort  { | leftval, rightval | rightval[1][:rating]<=>leftval[1][:rating] }

puts "SORTED HASH"
sorted_hash.each do |local|
  puts local
end
3
12.12.2008 07:44:30
Здесь это не будет иметь большого значения, но #sort, как правило, неэффективен для вычисляемых полей. Это потому, что он пересчитает критерии сортировки для каждого сравнения. #sort_by вычисляет критерии только один раз для каждого элемента в исходном массиве
Gareth 12.12.2008 07:56:35