Skip to content

Commit

Permalink
Handle duplicate values in arrays correctly.
Browse files Browse the repository at this point in the history
  • Loading branch information
abnerqian committed Jan 19, 2016
1 parent c7c30b7 commit 362db20
Showing 1 changed file with 22 additions and 4 deletions.
26 changes: 22 additions & 4 deletions lib/easy_diff/core.rb
Expand Up @@ -30,8 +30,8 @@ def self.easy_diff(original, modified)
end

elsif original.is_a?(Array) && modified.is_a?(Array)
removed = original - modified
added = modified - original
removed = subtract_arrays(original, modified)
added = subtract_arrays(modified, original)

elsif original != modified
removed = original
Expand All @@ -46,7 +46,7 @@ def self.easy_unmerge!(original, removed)
keys_in_common = original.keys & removed.keys
keys_in_common.each{ |key| original.delete(key) if easy_unmerge!(original[key], removed[key]).nil? }
elsif original.is_a?(Array) && removed.is_a?(Array)
original.reject!{ |e| removed.include?(e) }
subtract_arrays!(original, removed)
original.sort_by! { |item|
item.is_a?(Hash) ? item.sort : item
}
Expand All @@ -63,7 +63,7 @@ def self.easy_merge!(original, added)
added_keys = added.keys
added_keys.each{ |key| original[key] = easy_merge!(original[key], added[key])}
elsif original.is_a?(Array) && added.is_a?(Array)
original |= added
original += added
original.sort_by! { |item|
item.is_a?(Hash) ? item.sort : item
}
Expand All @@ -81,5 +81,23 @@ def self.easy_clone(original)
def self._empty?(obj)
(obj.is_a?(Hash) || obj.is_a?(Array)) && obj.empty?
end

# The regular array difference does not handle duplicate values in the way that is needed for this library.
# Examples:
# subtract_arrays([1, 1, 2, 3], [1, 2]) => [1, 3]
# subtract_arrays([3, 3, 3, 4], [3, 4, 5]) => [3, 3]
# Shamelessly stolen from http://stackoverflow.com/questions/3852755/ruby-array-subtraction-without-removing-items-more-than-once
def self.subtract_arrays! arr1, arr2
counts = arr2.inject(Hash.new(0)) { |h, v| h[v] += 1; h }
arr1.reject! { |e| counts[e] -= 1 unless counts[e].zero? }
end

# Non-destructive version of above method.
def self.subtract_arrays arr1, arr2
cloned_arr1 = easy_clone(arr1)
subtract_arrays!(cloned_arr1, arr2)

cloned_arr1
end
end
end

0 comments on commit 362db20

Please sign in to comment.