按键排序哈希,在 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
【问题讨论】:
我不确定对哈希进行排序有多大好处,除非您使用each
或 each_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
注意: 注意:> Ruby 2.1array = [["key", "value"]]
hash = Hash[array]
hash #=> "key"=>"value"
[["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=>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(&:last).to_h => "b"=>10, "a"=>1000, "c"=>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<=>z.to_h
(已测试 2.1.10、2.3.3)
@whitehat101 你是对的。我有一个错误(a
是一个数组,而不仅仅是键)。我删除了我的评论。
以防万一其他人正在寻找一种方法来对哈希数组进行排序,这将起到作用(其中 h 是数组):h.map(&:sort).map(&:to_h)
。
我不会使用这个解决方案,因为它不是最快的。对于小散列,这很好,但对于几千个键,它比h.keys.sort.map |k| [k, h[k]] .to_h
慢 10 倍。不确定 C 级别的差异在哪里,但在基准测试中非常清楚。甚至sort_by(&: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 中返回哈希的主要内容,如果未能解决你的问题,请参考以下文章