Сортировка хэша по ключу, возврат хеша в Ruby

Будет ли это лучший способ сортировки хеша и вернуть объект Hash (вместо 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}

Ответ 1

В Ruby 2.1 это просто:

h.sort.to_h

Ответ 2

Примечание. Ruby >= 1.9.2 имеет хэширование, сохраняющее порядок: вставляются ключи заказа, это порядок, который они перечисляют. Приведенное ниже относится к более старым версиям или к обратному совместимому коду.

Не существует понятия отсортированного хэша. Так что нет, что вы делаете неправильно.

Если вы хотите, чтобы он отсортировался для отображения, верните строку:

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

или, если вы хотите, чтобы клавиши были в порядке:

h.keys.sort

или, если вы хотите получить доступ к элементам в порядке:

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

но в целом, нет смысла говорить о сортированном хеше. Из docs: "Порядок, в котором вы проходите хэш с помощью ключа или значения, может показаться произвольным и, как правило, не будет в порядке вставки". Поэтому вставка ключей в определенном порядке в хэш не поможет.

Ответ 3

Я всегда использовал sort_by. Вам нужно обернуть вывод #sort_by с помощью Hash[], чтобы он выводил хэш, иначе он выводит массив массивов. В качестве альтернативы для этого вы можете запустить метод #to_h в массиве кортежей, чтобы преобразовать их в структуру k=>v (хэш).

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

В "есть аналогичный вопрос: как сортировать символ "Ruby Hash" по номеру?".

Ответ 4

Нет, это не (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)

Для больших хэшей разница вырастет до 10x и более

Ответ 5

Вы дали лучший ответ себе в OP: Hash[h.sort] Если вы жаждете больше возможностей, здесь вы можете изменить исходный хэш на месте, чтобы он отсортировался:

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

Ответ 6

ActiveSupport:: OrderedHash - это еще один вариант, если вы не хотите использовать ruby ​​1.9.2 или сворачиваете свои собственные обходные пути.

Ответ 7

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

Ответ 8

У меня была такая же проблема (мне пришлось сортировать мое оборудование по их имени), и я решил вот так:

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

@equipments - хэш, который я построил на своей модели и возвращаюсь на свой контроллер. Если вы вызываете .sort, он будет сортировать хэш на основе его значения ключа.

Ответ 9

Мне понравилось решение в предыдущем сообщении.

Я сделал мини-класс, называемый class AlphabeticalHash. Он также имеет метод под названием ap, который принимает один аргумент, a Hash, как вход: ap variable. Сродни pp (pp variable)

Но он будет (попробуйте и) распечатать в алфавитном списке (его ключи). Dunno, если кто-то еще хочет использовать это, он доступен как драгоценный камень, вы можете установить его как таковой: gem install alphabetical_hash

Для меня это достаточно просто. Если другим нужна дополнительная функциональность, пусть я знаю, я включу его в камень.

EDIT: кредит отправляется Peter, который дал мне эту идею.:)