Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Flatten deeply-nested hashes
def recursive_flatten(input, keys = [], acc = {})
input.keys.each do |k|
result_key = keys + [k]
if input[k].is_a?(Hash)
recursive_flatten(input[k], keys + [k], acc)
elsif input[k].is_a?(Array) && input[k].any? {|v| v.is_a?(Hash) }
input[k].each_with_index do |array_value, index|
result_key_with_index = keys + [k, "[#{index}]"]
if array_value.is_a?(Hash)
recursive_flatten(array_value, [result_key_with_index.join(".")], acc)
else
acc[result_key_with_index.join(".")] = array_value
end
end
else
acc[result_key.join(".")] = input[k]
end
end
acc
end
if STDIN.tty?
else
require 'json'
puts JSON.dump(recursive_flatten(JSON.parse($stdin.read)))
end
require 'rspec'
require_relative 'hash_flattener'
RSpec.describe "recursive_flatten" do
it "works with simple structures" do
value = {
foo: 1,
bar: 2
}
expect(recursive_flatten(value)).to eq({ "foo" => 1, "bar" => 2 })
end
it "works with more complex structures" do
value = {
foo: {
bar: 1
},
baz: 2
}
expect(recursive_flatten(value)).to eq({ "foo.bar" => 1, "baz" => 2 })
end
it "works with very deeply nested structures" do
value = {
foo: {
blah: "value",
blarg: [1, 2, 3],
bar: {
baz: {
buzz: true,
other: false
}
}
},
baz: 2
}
expect(recursive_flatten(value)).to eq({
"foo.blah" => "value",
"foo.blarg" => [1, 2, 3],
"foo.bar.baz.buzz" => true,
"foo.bar.baz.other" => false,
"baz" => 2
})
end
it "works with arrays" do
value = {
foo: [
1,
"two",
{ three: [1, { two: 2 }, 3] }
]
}
expect(recursive_flatten(value)).to eq({
"foo.[0]" => 1,
"foo.[1]" => "two",
"foo.[2].three.[0]" => 1,
"foo.[2].three.[1].two" => 2,
"foo.[2].three.[2]" => 3,
})
end
it "works with the weirdest ones possible" do
value = {
foo: [
1,
"two",
{ three: [1, { two: 2 }, 3] },
[1,2,3],
{ four: true, five: false, six: { six: 6 }, seven: [7, { eight: 8 }] },
]
}
expect(recursive_flatten(value)).to eq({
"foo.[0]" => 1,
"foo.[1]" => "two",
"foo.[2].three.[0]" => 1,
"foo.[2].three.[1].two" => 2,
"foo.[2].three.[2]" => 3,
"foo.[3]" => [1, 2, 3],
"foo.[4].four" => true,
"foo.[4].five" => false,
"foo.[4].six.six" => 6,
"foo.[4].seven.[0]" => 7,
"foo.[4].seven.[1].eight" => 8,
})
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment