Extract all complete key sequences from a multi-dimensional hash (with the last key not pointing to another hash; cf. h[1][2][3] vs h[1][2][3][4] below).
class Hash
def extract_keys
keys = []
each_pair do |k1, v1|
if v1.is_a?(Hash)
v1.each_pair { |k2, v2|
if !v2.is_a?(Hash) then keys << [k1, k2]; next end
v2.each_pair { |k3, v3|
if !v3.is_a?(Hash) then keys << [k1, k2, k3]; next end
v3.each_pair { |k4, v4|
if !v4.is_a?(Hash) then keys << [k1, k2, k3, k4]; next end
v4.each_pair { |k5, v5|
if !v5.is_a?(Hash) then keys << [k1, k2, k3, k4, k5]; next end
v5.each_pair { |k6, v6|
if !v6.is_a?(Hash) then keys << [k1, k2, k3, k4, k5, k6]; next end
} } } } }
else
keys << [k1]
end
end
keys
end
def all_values
extract_keys.map do |subar|
key = ""
subar.size.times { |i| key << "[subar[#{i}]]" }
hash_str = "self" << key << " rescue nil"
hash_value = eval(hash_str)
end
end
def each_path
raise ArgumentError unless block_given?
self.class.each_path(self) { |path, object| yield(path, object) }
end
protected
def self.each_path(object, path = [], &block)
if object.is_a?(Hash)
object.each do |key, value|
self.each_path(value, [path , key].flatten, &block)
end
else
yield(path, object)
end
end
end
h = {"a"=>"b", "c"=>"d", 1=>{2=>{"e"=>"f", 3=>{4=>"value"}}}}
puts h[1][2].class # Hash
puts h[1][2]["e"].class # String
extracted_keys = h.extract_keys
puts extracted_keys.inspect
puts h[1][2].has_key?("e")
puts extracted_keys.include?([1, 2, "e"])
h = {700=>{4=>"value"}, "a"=>"b", 3=>{4=>"value"}, "c"=>"d", 1=>{2=>{"e"=>"f", 3=>{4=>"value"}, 300=>{4=>"value"}}}}
p h
p h.extract_keys
p h.all_values
paths = []
complex_hash = Hash[
:a => { :aa => '1', :ab => '2' },
:b => { :ba => '3', :bb => '4' }
]
complex_hash.each_path { |path, value| paths << [ path, value ] }
p paths
puts
h = {"a"=>"b", "c"=>"d", 1=>{2=>{"e"=>"f", 3=>{4=>"value"}}}}
h = {"a"=>"b", "l" => lambda { |x| x+1 }, 1=>{2=>{"e"=>"f", 3=>{4=>"value"}}}}
h = {700=>{4=>"value"}, "a"=>"b", nil => "NILVALUE", 3=>{4=>"value"}, "c"=>"d", 1=>{2=>{"e"=>"f", 3=>{4=>"value"}, 300=>{4=>"value"}}}}
p h
p h.extract_keys
keys = []
h.each_path { |path, value| keys << path }
p keys
paths = []
h.each_path { |path, value| paths << [ path, value ] }
p paths
vals = []
h.each_path { |path, value| vals << value }
p vals
p h.all_values