Почему массив ключей и значений класса Ruby из 1000 хэшей всегда находится в определенном порядке?

Скажите, есть ли массив из 1000 хэшей, с парами, такими как {:id => 1, :name => 'something', :created_at => '2010-08-18'}

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

(я думал о отображении :id to 10, and :name to 20, and :create_at to 30, а затем сортировал ключи по этим отображаемым значениям, так что: id до: name и до: created_at)

(хеш распечатывается a_hash.each_pair do |k, v| ...)

Ответ 1

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

Ответ 2

В hashmaps Ruby (и hashmaps вообще) не подразумевается порядок ключей. Они, однако, реализованы таким образом, чтобы получить значение, заданное ключом, эффективную операцию (время амортизации O (1)).

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

Ответ 3

документация на ruby-doc.org для ruby ​​1.9 (не уверен, что это 1.9.0 или 1.9.1) неправильно говорит

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

Но 1.9.1 новости говорит

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

Я взглянул на ствол рубина (что развивается), и он говорит

Хэши перечисляют свои значения в чтобы соответствующие ключи были вставлены.

Изменение документации было в 25 сентября 2009 г., в котором исправлялась некорректная документация.

Я не уверен на 100%, что упорядоченное перечисление является частью спецификации ruby ​​1.9.1. Rubyspec будет одним из способов проверки. Но если основная реализация дает контракт, тогда вы ожидаете, что любая другая реализация будет соблюдать этот контракт, если он явно не говорит иначе.

Ответ 4

Ruby не гарантирует упорядочение ключей Hash, хотя Ruby 1.9 сохраняет порядок вставки.

Если вы хотите обработать хэш-ключи в определенном, но произвольном порядке, лучшим способом является создание массива с указанием порядка. Таким образом, у вас может быть массив типа [:id, :name, :create_at]. Если вы хотите обработать хеш, скажем, в алфавитном порядке, вы можете просто использовать sort, и он даст вам массив пар ключ-значение в порядке.

Ответ 5

Почему это и на что можно рассчитывать?

Любой хеш будет иметь "естественный вид".

"Естественная сортировка" поддерживается либо по мере того, как каждый элемент вставлен, либо выполняется перед первым поиском.

Если нет естественной сортировки, возвращающей значение, соответствующее определенному ключу, потребуется исчерпывающий поиск.

Исчерпывающий поиск, конечно, будет проводить n сравнений, где n - количество элементов в хэше. (например, 65536 элементов, которые искали в 65536 сравнениях.)

С другой стороны, если хэш сортируется по алфавиту с помощью KEY, тогда двоичный поиск может найти соответствие в сравнении с LOG2 (n). (например, 65536 элементов, которые были найдены в 16 сравнениях.)

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

например. В следующей частичной реализации пары ключ/значения хранятся как объекты в базовом массиве.

myArray[0] = {"b", "Skies"}
myArray[1] = {"c", "dog"}
myArray[2] = {"a", "Jax"}
myArray[3] = {"d", "gone"}
myArray[4] = {"r", "run"}
myArray[5] = {"q", "quit"}

второй массив, к которому разработчик Ruby не имеет доступа, сохраняет сортировку.

sortArray[0] = 2
sortArray[1] = 0
sortArray[2] = 1
sortArray[3] = 3
sortArray[4] = 4 
sortArray[5] = 5 

Таким образом, внутренне к хэш-объекту

for(i=0 to 5) 
    print myArray[sortArray[i]]

напечатает отсортированный массив.

Спецификация Ruby, по-видимому, не указывает, какой метод использовать, сортировка по ключу, скрытый вид или какой-либо другой метод, поэтому нет, вы не можете рассчитывать на естественный вид.