按键排序哈希,在 Ruby 中返回哈希

Posted

技术标签:

【中文标题】按键排序哈希,在 Ruby 中返回哈希【英文标题】:Sort hash by key, return hash in Ruby 【发布时间】:2011-05-19 09:08:48 【问题描述】:

这是对哈希进行排序并返回哈希对象(而不是数组)的最佳方法吗:

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

【问题讨论】:

我不确定对哈希进行排序有多大好处,除非您使用 eacheach_pair 对其进行迭代。即使那样,我可能仍然会抓取键,对它们进行排序,然后根据需要遍历它们以获取值。这可确保代码在较旧的 Ruby 上正常运行。 在 ruby​​ 1.9 中也有意义。我有一个约会集合,按日期(作为键)分组,来自 db,我通过 ruby​​ 手动排序。例如。 "2012-09-22": [...], "2012-09-30": [...], "2012-10-12": [...] 是的,我发现您的 Hash[h.sort] 过程比排序键然后通过排序键再次访问哈希更有效。 "What is the fastest way to sort a Hash? 会很有用。 您已经思考了几年的解决方案,您准备好接受答案了吗? ;-) 【参考方案1】:

我借用了 Boris Stitnicky 的灵感解决方案,将就地 sort! 方法修补到 Hash

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

【讨论】:

【参考方案2】:

key排序hash,返回Ruby中的hash

使用解构和Hash#sort

hash.sort  |(ak, _), (bk, _)| ak <=> bk .to_h

可枚举#sort_by

hash.sort_by  |k, v| k .to_h

Hash#sort 默认行为

h =  "b" => 2, "c" => 1, "a" => 3  
h.sort         # e.g. ["a", 20] <=> ["b", 30]
hash.sort.to_h #=>  "a" => 3, "b" => 2, "c" => 1 

注意:

array = [["key", "value"]] 
hash  = Hash[array]
hash #=> "key"=>"value"

注意:> Ruby 2.1

[["key", "value"]].to_h #=> "key"=>"value"

【讨论】:

如果不使用v,你应该在前缀hash.sort_by |k, _v| k .to_h【参考方案3】:

我遇到了同样的问题(我必须按照他们的名字对我的设备进行分类),我这样解决了:

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

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

【讨论】:

【参考方案4】: 如果您不想使用 ruby​​ 1.9.2 或推出自己的解决方法,

ActiveSupport::OrderedHash 是另一种选择。

【讨论】:

链接失效 我修复了指向 Google 的链接,以防某些历史学家想要研究过去如何做到这一点。但是现在任何人都应该使用更新版本的 Ruby。【参考方案5】:

我一直使用sort_by。您需要用Hash[] 包装#sort_by 输出以使其输出哈希,否则它会输出一个数组数组。或者,要完成此操作,您可以在元组数组上运行 #to_h 方法,将它们转换为 k=&gt;v 结构(哈希)。

hsh ="a" => 1000, "b" => 10, "c" => 200000
Hash[hsh.sort_by|k,v| v] #or hsh.sort_by|k,v| v.to_h

“How to sort a Ruby Hash by number value?”中有类似的问题。

【讨论】:

在哈希上使用sort_by 将返回一个数组。您需要再次将其映射为哈希。 Hash[hsh.sort_by|k,v| v] 是的,我认为枚举器类将哈希解释为数组 对,排序是​​基于值:hsh.sort_by(&amp;:last).to_h =&gt; "b"=&gt;10, "a"=&gt;1000, "c"=&gt;200000. 请注意,调用to_h 仅在 Ruby 2.1.0+ 中支持 评论有错别字,更正:sort_by|k,v| v.to_h)【参考方案6】:

在 Ruby 2.1 中很简单:

h.sort.to_h

【讨论】:

@zachaysan 但它确实有效:h.sort|a,z|a&lt;=&gt;z.to_h(已测试 2.1.10、2.3.3) @whitehat101 你是对的。我有一个错误(a 是一个数组,而不仅仅是键)。我删除了我的评论。 以防万一其他人正在寻找一种方法来对哈希数组进行排序,这将起到作用(其中 h 是数组):h.map(&amp;:sort).map(&amp;:to_h) 我不会使用这个解决方案,因为它不是最快的。对于小散列,这很好,但对于几千个键,它比h.keys.sort.map |k| [k, h[k]] .to_h 慢 10 倍。不确定 C 级别的差异在哪里,但在基准测试中非常清楚。甚至sort_by(&amp;:first) 也快得多。 @KaplanIlya 可能区别在于对键进行排序与​​对整个哈希进行排序。尽管如此,我还是更喜欢简单和简洁,并且会在更复杂的情况下寻求这个解决方案,除非哈希值足够大并且有明显的差异。如果是这样的话,对哈希进行排序可能不是最好的架构决策:)【参考方案7】:

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

但总而言之,谈论排序哈希是没有意义的。来自docs,“通过键或值遍历散列的顺序可能看起来是任意的,并且通常不会按照插入顺序。”因此,以特定顺序将键插入哈希将无济于事。

【讨论】:

这是正确的。我建议使用 RBtree gem 在 ruby​​ 中获得有序集功能。 将保留从 1.9.2 开始的哈希插入顺序。见redmine.ruby-lang.org/issues/show/994 “将保留从 1.9.2 开始的哈希插入顺序。”,很甜蜜。 我的第一条评论(感觉很有趣):例如,对于早于 1.9.2 的 Ruby 版本,依赖哈希排序会无声且不可预测地中断。 这个答案是如何得到大约 20 个 +1 的,甚至没有回答 OP 问题的两个部分之一? “1)那(OP示例)是否是对哈希进行排序的最佳方法,2)并返回哈希对象”?我不羡慕+1 :) 就在阅读答案之后,我仍然留下了原始问题。另外,如果重点是没有排序哈希之类的东西,请查看 cmets 以选择此问题的答案***.com/questions/489139/…【参考方案8】:
@ordered = 
@unordered.keys.sort.each do |key|
  @ordered[key] = @unordered[key]
end

【讨论】:

如果 ruby​​ 没有像 Hash#sort_by 这样的方法,你会这样做【参考方案9】:

不,不是(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 倍甚至更多

【讨论】:

【参考方案10】:

你在 OP 中给了自己最好的答案:Hash[h.sort]如果你渴望更多的可能性,这里是对原始哈希的就地修改以使其排序:

h.keys.sort.each  |k| h[k] = h.delete k 

【讨论】:

对于好奇的人,这比 Ruby 1.9.3 上 ***.com/a/17331221/737303 中的“键排序”运行速度略快。【参考方案11】:

我喜欢之前帖子中的解决方案。

我做了一个迷你班,叫它class AlphabeticalHash。它还有一个名为ap 的方法,它接受一个参数Hash 作为输入:ap variable。类似于 pp (pp variable)

但它会(尝试并)按字母列表(其键)打印。不知道如果其他人想使用它,它可以作为 gem 使用,你可以这样安装它:gem install alphabetical_hash

对我来说,这很简单。如果其他人需要更多功能,让 我知道,我会将它包含在 gem 中。

编辑:感谢Peter,他给了我这个想法。 :)

【讨论】:

以上是关于按键排序哈希,在 Ruby 中返回哈希的主要内容,如果未能解决你的问题,请参考以下文章

Ruby - 按值按降序排序哈希值

如果值递归包含字符串,Ruby 返回***哈希键

c# 按键排序的哈希表

如何按值按降序对哈希进行排序并在 ruby​​ 中输出哈希?

Ruby更改哈希的键值

雷林鹏分享:Ruby 哈希(Hash)