Created
July 18, 2016 10:24
-
-
Save ProGM/79e72876dbbcbbd79a2beec893c4f6e8 to your computer and use it in GitHub Desktop.
Revisions
-
ProGM created this gist
Jul 18, 2016 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,104 @@ 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