Last active
December 17, 2015 03:09
-
-
Save dimitarvp/5541709 to your computer and use it in GitHub Desktop.
Full source of an answer I posted here: http://stackoverflow.com/questions/16408563/efficiently-building-a-file-system-tree-structure-with-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
require 'awesome_print' | |
input = <<TEXT | |
2 1 app/assets/javascripts/bar.js | |
16 25 app/assets/javascripts/baz.js.coffee | |
1 1 app/assets/javascripts/foo.js.coffee | |
4 9 app/controllers/bar_controller.rb | |
3 2 app/controllers/baz_controller.rb | |
11 0 app/controllers/foo_controller.rb | |
3 2 db/schema.rb | |
41 1 lib/foobar.rb | |
12 7 lib/tasks/cache.rake | |
5 13 lib/tasks/import.rake | |
TEXT | |
# totals: add: 98, del: 61 | |
expected = | |
[ | |
{ name: "app", | |
add: 37, | |
del: 38, | |
children: [ | |
{name: "assets", add: 19, del: 27, children: [ | |
{name: "javascripts", add: 19, del: 27, children: [ | |
{name: "bar.js", add: 2, del: 1}, | |
{name: "baz.js.coffee", add: 16, del: 25}, | |
{name: "foo.js.coffee", add: 1, del: 1} | |
] | |
}, | |
] | |
}, | |
{name: "controllers", add: 18, del: 11, children: [ | |
{name: "bar_controller.rb", add: 4, del: 9}, | |
{name: "baz_controller.rb", add: 3, del: 2}, | |
{name: "foo_controller.rb", add: 11, del: 0}, | |
] | |
}, | |
] | |
}, | |
{ add: 3, | |
del: 2, | |
name: "db", | |
children: [ {name: "schema.rb", add: 3, del: 2} ] | |
}, | |
{ add: 58, | |
del: 21, | |
name: "lib", | |
children: [ | |
{name: "foobar.rb", add: 41, del: 1}, | |
{name: "tasks", add: 17, del: 20, children: | |
[ {name: "cache.rake", add: 12, del: 7}, | |
{name: "import.rake", add: 5, del: 13} ] } | |
] | |
} | |
] | |
def git_diffnum_parse_paths(list, depth, out) | |
to = 1 | |
base = list.first[:name][depth] | |
while list[to] and list[to][:name][depth] == base do | |
to += 1 | |
end | |
if list.first[:name][depth+1] | |
out << {name: base, add: 0, del: 0, children: []} | |
# Common directory found for the first N records; recurse deeper. | |
puts "#{' '*depth}#{base} (0-#{to-1})" | |
git_diffnum_parse_paths(list[0..to-1], depth + 1, out.last[:children]) | |
add = del = 0 | |
out.last[:children].each do |x| add += x[:add].to_i; del += x[:del].to_i; end | |
out.last[:add] = add | |
out.last[:del] = del | |
else | |
# It's a file, we can't go any deeper. | |
#puts "#{' '*depth}#{base}" | |
puts list.first | |
out << {name: list.first[:name].last, add: list.first[:add].to_i, del: list.first[:del].to_i} | |
end | |
if list[to] | |
# Recurse in to try find common directories for the deeper records. | |
#puts "#{' '*depth}#{list[to][:name][depth]} (#{to}-#{list.size-1})" | |
git_diffnum_parse_paths(list[to..-1], depth, out) | |
end | |
nil | |
end | |
def to_git_diffnum_tree(txt) | |
items = txt.split("\n") | |
.map { |line| line.split } | |
.map { |line| {add: line[0].to_i, del: line[1].to_i, name: line[2].split('/') } } | |
.sort_by { |item| item[:name] } | |
out = [] | |
git_diffnum_parse_paths(items, 0, out) | |
out | |
end | |
out = to_git_diffnum_tree(input) | |
puts; ap out; puts | |
puts; puts "Expected result:"; puts expected.inspect | |
puts; puts "Actual result: "; puts out.inspect | |
puts; puts "Are expected and actual results identical: #{expected == out}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment