这是对哈希进行排序并返回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}

当前回答

不,它不是(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)

对于较大的散列,差异将增长到10倍甚至更多

其他回答

我也遇到过同样的问题(我必须把我的设备按名字分类),我是这样解决的:

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

@equipments是我在模型上构建并返回到控制器上的哈希值。如果你调用.sort,它会根据它的键值对哈希进行排序。

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

如果你不想使用ruby 1.9.2或使用你自己的变通方法,ActiveSupport::OrderedHash是另一个选择。

注意: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

但总的来说,谈论一个排序的哈希是没有意义的。从文档中可以看出,“按键或值遍历哈希的顺序似乎是任意的,通常不是插入顺序。”因此,以特定顺序向散列中插入键是没有用的。

我借用Boris Stitnicky的灵感解决方案来修补一个就地排序!方法:

def sort!
  keys.sort!.each { |k| store k, delete(k) }
  self
end