Created
July 5, 2018 19:48
-
-
Save joshuaclayton/12e224cf745a2500713b4741ac7584c0 to your computer and use it in GitHub Desktop.
Flatten deeply-nested hashes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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