为什么您希望特定的键/值对在哈希中排在第一位?哈希不需要排序,因为您可以随时直接访问任何元素而无需任何额外费用。
如果您需要按顺序检索元素,然后获取键并对列表进行排序,然后迭代该列表,或者使用values_at:
foo = {
'z' => 1,
'a' => 2
}
foo_keys = foo.keys.sort # => ["a", "z"]
foo_keys.map{ |k| foo[k] } # => [2, 1]
foo.values_at(*foo_keys) # => [2, 1]
哈希会记住它们的插入顺序,但你不应该依赖它;如果您稍后插入某些内容,并且其他语言不支持它,那么订购哈希也无济于事。相反,可以根据需要对键进行排序,并使用该列表来检索值。
如果你想强制一个键是第一个以便首先检索它的值,那么考虑这个:
foo = {
'z' => 1,
'a' => 2,
'w' => 3,
}
foo_keys = foo.keys # => ["z", "a", "w"]
foo_keys.unshift(foo_keys.delete('w')) # => ["w", "z", "a"]
foo_keys.map{ |k| foo[k] } # => [3, 1, 2]
foo.values_at(*foo_keys) # => [3, 1, 2]
如果你想要一个排序的键列表,其中一个强制到一个位置:
foo_keys = foo.keys.sort # => ["a", "w", "z"]
foo_keys.unshift(foo_keys.delete('w')) # => ["w", "a", "z"]
foo_keys.map{ |k| foo[k] } # => [3, 2, 1]
foo.values_at(*foo_keys) # => [3, 2, 1]
RE 你的第一段:尽管哈希是有序的,特别是因为这是一个常见的要求,并且哈希在 Ruby 中占据了如此多的角色。即使其他语言不支持这种行为,在 Ruby 中对哈希进行排序也没有什么坏处。
没有排序,就像排序一样,而是记住他们的插入顺序。来自the documentation:
哈希按照插入相应键的顺序枚举它们的值。
这很容易测试/证明:
foo = {z:0, a:-1} # => {:z=>0, :a=>-1}
foo.to_a # => [[:z, 0], [:a, -1]]
foo[:b] = 3
foo.merge!({w:2})
foo # => {:z=>0, :a=>-1, :b=>3, :w=>2}
foo.to_a # => [[:z, 0], [:a, -1], [:b, 3], [:w, 2]]
foo.keys # => [:z, :a, :b, :w]
foo.values # => [0, -1, 3, 2]
如果对哈希进行排序,foo.to_a 会以某种方式进行整理,即使在添加了额外的键/值对之后也是如此。相反,它保留在其插入顺序中。基于键的有序散列会将a:-1 移动到第一个元素,就像基于值的有序散列一样。
如果哈希是有序的,并且如果它很重要,我们将有一些方法告诉哈希它的顺序是什么,升序或降序,或者根据键或值进行某种特殊的顺序。相反,我们没有这些东西,只有从 Enumerable 继承的 sort 和 sort_by 方法,这两个方法都将哈希转换为数组并将其排序并返回数组,因为数组 可以 从订单中受益。
也许您正在考虑 Java,它具有 SortedMap,并提供了这些功能:
进一步提供其键的总排序的 Map。映射是根据其键的自然顺序排序的,或者由通常在排序映射创建时提供的比较器排序。此顺序在遍历已排序地图的集合视图(由 entrySet、keySet 和 values 方法返回)时反映出来。提供了几个额外的操作来利用排序。
同样,由于 Ruby 的 Hash 不会超出其插入顺序进行排序,因此我们没有这些功能。