2014-12-09 4 views
12

Я пытаюсь сортировать хеш по алфавиту с помощью ключа, но я не могу найти способ сделать это, не создавая свой собственный класс сортировки. Я нашел код ниже для сортировки по значению, если это целое число, и я пытаюсь его изменить, но не повезло.Как отсортировать Ruby Hash в алфавитном порядке с помощью клавиш

temp["ninjas"]=36 
temp["pirates"]=12 
temp["cheese"]=222 
temp.sort_by { |key, val| key } 

Моя цель - заказать хэширование по ключу, а затем вывести значения. Мне придется делать это несколько раз с разными хэш-ордерами, но с теми же значениями.

+1

код, как представляется, сделать то, что вы просили. Не могли бы вы отредактировать вопрос, чтобы включить ожидаемый результат? –

+0

Я сделал предположение, что вы хотите, чтобы ваш вывод был другим хэшем. Было бы хорошо видеть, что в вопросе, если это так (тогда вопрос и ответ совпадут). –

+1

Что вы хотите в качестве вывода? Хэши на самом деле не отсортированы (они, по порядку вставки, с Ruby 1.9+). Что конкретно вы пытаетесь сделать? –

ответ

21

Предполагая, что вы хотите, чтобы выход был хешем, который будет перебирать ключи в отсортированном порядке, тогда вы почти находитесь. Hash#sort_by возвращает ArrayArray s, а внутренние массивы - все два элемента.

У Ruby's Hash есть конструктор, который может потреблять этот выход.

Попробуйте это:

temp = Hash[ temp.sort_by { |key, val| key } ] 

Если ваш хэш перепутал ключевых типов, это не будет работать (Ruby не будет автоматически сортировать между String s и Symbol s к примеру), и вы получите сообщение об ошибке, как сравнение Symbol с String не удалось (ArgumentError). Если это так, вы можете изменить приведенное выше значение на

temp = Hash[ temp.sort_by { |key, val| key.to_s } ] 

, чтобы обойти проблему. Однако следует предупредить, что ключи по-прежнему сохраняют свои исходные типы, которые могут вызвать проблемы с допущениями в более позднем коде. Кроме того, большинство встроенных классов поддерживают метод .to_s, поэтому вы можете получить от него нежелательные результаты (например, неожиданный порядок сортировки для цифровых клавиш или других неожиданных типов).

Вы могли бы, в дополнение, конвертировать ключи Strings с чем-то вроде этого:

temp = Hash[ temp.map { |key, val| [key.to_s, val] }.sort ] 

. , , хотя этот подход потеряет информацию о типе исходного ключа, что делает невозможным надежное обращение к исходным данным.

+0

Я пробовал свой код, но я получил: в 'sort_by': сравнение Symbol с String не удалось (ArgumentError) – Rilcon42

+0

Ваш хэш имеет смешанные типы ключей, и у вас будет эта проблема, однако вы хотите их отсортировать. Вы можете изменить его на 'temp = Hash [temp.sort_by {| key, val | key.to_s}] ', чтобы обойти проблему, но будьте осторожны, это изменит клавиши Symbol в Strings. , , если вы действительно хотите работать с данными в отсортированном порядке, вам нужно будет выбрать один тип данных для ваших ключей и придерживаться его –

+0

, не могли бы вы обновить свой ответ, чтобы отметить, как устранить проблему для будущих пользователей, которые может не читать комментарии? Благодаря! – Rilcon42

4

Ruby's Hash запоминает его порядок вставки в настоящее время, но ранее Rubies < v1.9 нет. Но, не утруждайте себя сортировкой хэша, поскольку нет никакого преимущества для этого, потому что в основном Хэш представляет собой структуру с произвольным доступом. Это означает, что все элементы доступны в любое время, и не будет иметь значения, является ли первый или последний, вы можете получить к нему доступ точно так же.

Это не похоже на массив, который действует как последовательный/текстовый файл или цепочка или очередь, и вам нужно получить доступ к нему линейно, итерации по нему, что в этот момент порядок элементов имеет большое значение.

Итак, с хэшем, получить ключи, отсортировать их и либо перебрать по списку ключей, либо использовать values_at для получения всех значений сразу. Например:

hash = { 
    'z' => 9, 
    'a' => 1 
} 

sorted_keys = hash.keys.sort # => ["a", "z"] 
sorted_keys.each do |k| 
    puts hash[k] 
end 
# >> 1 
# >> 9 

hash.values_at(*sorted_keys) # => [1, 9] 

Некоторые языки даже не позволит вам отсортировать хэш, и доступ к нему через отсортированный список ключей является единственным способом, чтобы извлечь элементы в порядке, так что это, вероятно, хорошая идея не привык полагаться на порядок пар ключ/значение, а вместо этого полагаться на клавиши.

+1

Ваше утверждение, что сортировка хэша «не имеет преимуществ», верна только в случае поиска. Если вы хотите узнать хэш х *. (например, создание md5 содержимого хэша), последовательный порядок является релевантным и необходимым. – MissingHandle

+0

Поскольку вопрос касается создания поисковых запросов, ваш комментарий имеет мало значения. Да, создание MD5 всего объекта иногда полезно, но так как большинство людей время извлекает значения, сортировка хэша не поможет. –

+0

Только пытался уточнить заявление, которое вы сделали, «не утруждайте себя сортировкой хэша, поскольку нет никаких преимуществ» для любых noobs, которые могли бы использовать их ум, расширенный по мере их изучения :). Ура! – MissingHandle

5
sorted_by_key = Hash[original_hash.sort] 

создаст новый Hash, вставив ключ/значение original_hash в алфавитном порядке по ключу. Хеши Ruby 2.x помнят порядок их вставки, поэтому этот новый хеш будет отображаться отсортированным по ключу, если вы его перечислите или выведете.

Если вы вставляете больше элементов в не алфавитном порядке, это, конечно, не будет выполнено.

Кроме того, предполагается, что исходные ключи хэша все сопоставимы/сопоставимы.

0

Вы можете создать новый пустой хеш для хранения отсортированных хэш-данных. Перейдите через возвращаемый массив и загрузите данные в новый хеш для хранения отсортированных хэш-данных.

temp = {} 
temp["ninjas"]=36 
temp["pirates"]=12 
temp["cheese"]=222 
temp = temp.sort_by { |key, val| key } 

temp_sorted = {} 
temp.each { |sub_arr| temp_sorted[sub_arr[0]] = sub_arr[1] } 
temp = temp_sorted 

температура теперь равны { "сыр" => 222, "Ниндзя" => 36, "пираты" => 12}

Смежные вопросы