为什么Ruby的1000个哈希数组的键和值对总是按特定顺序排列?

时间:2010-08-18 19:54:01

标签: ruby hash

假设是否存在1000个哈希数组,其中包含{:id => 1, :name => 'something', :created_at => '2010-08-18'}

这样的对

当我使用循环打印出那1000条记录时,据说,哈希的键/值对顺序不能得到保证,但是打印出来的表格总是以相同的顺序出现。为什么它可以被依靠?否则,有什么好的方法可以对键/值对进行排序?

(我考虑映射:id to 10, and :name to 20, and :create_at to 30,然后按这些映射值对键进行排序,以便:id在before:name之前,并且在before:created_at之前)

(哈希由a_hash.each_pair do |k, v| ...打印出来)

5 个答案:

答案 0 :(得分:3)

哈希的布局是 deterministic 。因此,对于特定版本的ruby,如果始终以相同的顺序添加/删除哈希的键,则哈希的布局将是相同的。这意味着迭代数组中的哈希将使键具有相同的顺序。

答案 1 :(得分:1)

Ruby hashmaps(和一般的hashmaps)没有隐含的键排序。然而,它们的实现方式使得检索给定键的值是一种有效的操作(摊销的O(1))时间。

因此,在底层实现中,键总是以相同的方式构造,这使得它们看起来有订单。

答案 2 :(得分:1)

ruby​​-doc.org上的documentation对于ruby 1.9(不确定它是1.9.0还是1.9.1)错误地说

  

遍历哈希的顺序   可能看起来像键或值   任意的,一般不会   在插入顺序中。

但1.9.1新闻says

  

哈希保留订单。它按键的顺序枚举其元素   插入

我看了红宝石的树干(正在开发的东西),它说

  

哈希列举了他们的价值观   订购相应的钥匙   插入

对文档的更改位于修复错误文档的September 25, 2009 commit中。

我不是100%确定有序枚举是ruby 1.9.1规范的一部分。 Rubyspec将是一种检查方式。但是,如果主要实施提供合同,那么除非明确说明,否则您希望任何其他实施都能遵守该合同。

答案 3 :(得分:0)

Ruby不保证对Hash密钥的排序,尽管Ruby 1.9确实保留了插入顺序。

如果要以特定但任意的顺序处理哈希的键,最好的方法是创建一个指定顺序的数组。所以你可能有一个像[:id, :name, :create_at]这样的数组。如果你想按字母顺序处理哈希,你可以使用sort,它会按顺序为你提供一组键值对。

答案 4 :(得分:0)

为什么它可以被依靠?

任何哈希都会有“自然排序”。

在插入每个元素时或在第一次搜索之前执行“自然排序”。

如果没有自然排序返回,则匹配特定键的值将需要进行详尽搜索。

当然,详尽的搜索会进行n次比较,其中n是散列中元素的数量。(例如,在65536次比较中搜索的65536个元素。)

另一方面,如果哈希按KEY按字母顺序排序,则二进制搜索可以在LOG2(n)比较中找到匹配项。 (例如,在16次比较中搜索了65536个元素。)

还有其他排序方法,但它们都需要一些初始排序。这种排序可能是一个隐藏索引的系统,它使键/值对元素保持未排序状态。

e.g。在以下部分实现中,键/值对作为对象存储在基础数组中。

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的规范显然没有指定使用哪种方法,按键排序,隐藏排序或其他方法,所以,不,你不能指望自然排序。