Skip to content

Instantly share code, notes, and snippets.

@albttx
Forked from ProGM/deep_merge_tree.rb
Created July 18, 2016 10:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save albttx/17a88713c8dcce9a937d0aa8f29f9d81 to your computer and use it in GitHub Desktop.
Save albttx/17a88713c8dcce9a937d0aa8f29f9d81 to your computer and use it in GitHub Desktop.
class Tree
attr_reader :data
def initialize(data)
@data = data
end
def +(other)
Tree.new(deep_merge(@data, other.is_a?(Tree) ? other.data : other))
end
delegate :empty?, to: :data
def replace(other)
@data.replace(other.data)
end
def root
level(0)
end
def levels
output = []
i = -1
while i += 1
current_level = level(i)
break if current_level.all?(&:nil?)
output << current_level
end
output
end
def level(level_number)
all_elements_at_level(@data, level_number)
end
private
def deep_merge(a, b)
case a
when Hash
return merge_hashes(a, b) if b.is_a?(Hash)
return merge_array_hash(b, a) if b.is_a?(Array)
[b, a]
when Array
return merge_arrays(a, b) if b.is_a?(Array)
return merge_array_hash(a, b) if b.is_a?(Hash)
[b] + a
else
return [a, b] if b.is_a?(Hash)
return [a] + b if b.is_a?(Array)
a == b ? a : [a, b]
end
end
def merge_array_hash(a, b)
if a.last.is_a? Hash
a[0...-1] + [merge_hashes(a.last, b)]
else
a + [b]
end
end
def merge_hashes(a, b)
a.deep_merge(b) do |_, this_val, other_val|
deep_merge(this_val, other_val)
end
end
def merge_arrays(a, b)
keys = merge_array_keys(a, b)
hashes = merge_hashes(a.last.is_a?(Hash) ? a.last : {}, b.last.is_a?(Hash) ? b.last : {})
if hashes.empty?
keys
else
(keys - hashes.keys) + [hashes]
end
end
def merge_array_keys(a, b)
(a.reject { |e| e.is_a?(Hash) } + b.reject { |e| e.is_a?(Hash) }).uniq
end
def all_elements_at_level(data, level_number)
return ground_level(data) if level_number == 0
case data
when Hash
data.map { |_, v| all_elements_at_level(v, level_number - 1) }
when Array
data.map { |e| all_elements_at_level(e, level_number) }.flatten
end
end
def ground_level(data)
case data
when Hash
data.keys
when Array
data.map { |e| all_elements_at_level(e, 0) }.flatten
else
data
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment