Ruby:获取哈希中的所有键(包括子键)

让我们有这个哈希:

hash = {"a" => 1, "b" => {"c" => 3}} hash.get_all_keys => ["a", "b", "c"] 

我怎么能得到所有键,因为hash.keys只返回["a", "b"]

这将为您提供任何嵌套级别的所有键的数组。

 def get_em(h) h.each_with_object([]) do |(k,v),keys| keys << k keys.concat(get_em(v)) if v.is_a? Hash end end hash = {"a" => 1, "b" => {"c" => {"d" => 3}}} get_em(hash) # => ["a", "b", "c", "d"] 

我发现grep在这里很有用:

 def get_keys(hash) ( hash.keys + hash.values.grep(Hash){|sub_hash| get_keys(sub_hash) } ).flatten end p get_keys my_nested_hash #=> ["a", "b", "c"] 

我喜欢这个解决方案,因为它很短,但读起来非常好。

 def get_all_keys(hash) hash.map do |k, v| Hash === v ? [k, get_all_keys(v)] : [k] end.flatten end 

请看下面的代码:

 hash = {"a" => 1, "b" => {"c" => 3}} keys = hash.keys + hash.select{|_,value|value.is_a?(Hash)} .map{|_,value| value.keys}.flatten p keys 

结果:

 ["a", "b", "c"] 

新的解决方案,考虑@ Bala的评论。

 class Hash def recursive_keys if any?{|_,value| value.is_a?(Hash)} keys + select{|_,value|value.is_a?(Hash)} .map{|_,value| value.recursive_keys}.flatten else keys end end end hash = {"a" => 1, "b" => {"c" => {"d" => 3}}, "e" => {"f" => 3}} p hash.recursive_keys 

结果:

 ["a", "b", "e", "c", "d", "f"] 
 class Hash def get_all_keys [].tap do |result| result << keys values.select { |v| v.respond_to?(:get_all_keys) }.each do |value| result << value.get_all_keys end end.flatten end end hash = {"a" => 1, "b" => {"c" => 3}} puts hash.get_all_keys.inspect # => ["a", "b", "c"] 

这是另一种方法:

 def get_all_keys(h) h.each_with_object([]){|(k,v),a| v.is_a?(Hash) ? a.push(k,*get_all_keys(v)) : a << k } end hash = {"a" => 1, "b" => {"c" => {"d" => 3}}} p get_all_keys(hash) # >> ["a", "b", "c", "d"] 

hash.keys是我看到的最简单的一个返回散列中键值的数组。

我确信有一个更优雅的解决方案,但这个选项有效:

 blah = {"a" => 1, "b" => {"c" => 3}} results = [] blah.each do |k,v| if v.is_a? Hash results << k v.each_key {|key| results << key} else results << k end end puts results 

保持键层次结构的版本

  • 适用于数组
  • 适用于嵌套哈希

keys_only.rb

 # one-liner def keys_only(h); h.map { |k, v| v = v.first if v.is_a?(Array); v.is_a?(Hash) ? [k, keys_only(v)] : k }; nil; end # nicer def keys_only(h) h.map do |k, v| v = v.first if v.is_a?(Array); if v.is_a?(Hash) [k, keys_only(v)] else k end end end hash = { a: 1, b: { c: { d: 3 } }, e: [{ f: 3 }, { f: 5 }] } keys_only(hash) # => [:a, [:b, [[:c, [:d]]]], [:e, [:f]]] 

PS:是的,它看起来像个词霸:D

额外奖励:在一个漂亮的嵌套列表中打印密钥

 # one-liner def print_keys(a, n = 0); a.each { |el| el.is_a?(Array) ? el[1] && el[1].class == Array ? print_keys(el, n) : print_keys(el, n + 1) : (puts " " * n + "- #{el}") }; nil; end # nicer def print_keys(a, n = 0) a.each do |el| if el.is_a?(Array) if el[1] && el[1].class == Array print_keys(el, n) else print_keys(el, n + 1) end else puts " " * n + "- #{el}" end end nil end > print_keys(keys_only(hash)) - a - b - c - d - e - f