class Hashdiff::LinearCompareArray
@private
Used to compare arrays in a linear complexity, which produces longer diffs than using the lcs algorithm but is considerably faster
Attributes
additions[R]
deletions[R]
differences[R]
expected_additions[RW]
new_array[R]
new_index[RW]
old_array[R]
old_index[RW]
options[R]
Public Class Methods
call(old_array, new_array, options = {})
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 8 def self.call(old_array, new_array, options = {}) instance = new(old_array, new_array, options) instance.call end
new(old_array, new_array, options)
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 44 def initialize(old_array, new_array, options) @old_array = old_array @new_array = new_array @options = { prefix: '' }.merge!(options) @additions = [] @deletions = [] @differences = [] end
Public Instance Methods
call()
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 13 def call return [] if old_array.empty? && new_array.empty? self.old_index = 0 self.new_index = 0 # by comparing the array lengths we can expect that a number of items # are either added or removed self.expected_additions = new_array.length - old_array.length loop do if extra_items_in_old_array? append_deletion(old_array[old_index], old_index) elsif extra_items_in_new_array? append_addition(new_array[new_index], new_index) else compare_at_index end self.old_index = old_index + 1 self.new_index = new_index + 1 break if iterated_through_both_arrays? end changes end
Private Instance Methods
append_addition(item, index)
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 138 def append_addition(item, index) key = Hashdiff.prefix_append_array_index(options[:prefix], index, options) additions << ['+', key, item] end
append_addititions_before_match(match_index)
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 122 def append_addititions_before_match(match_index) return unless match_index (new_index...match_index).each { |i| append_addition(new_array[i], i) } self.expected_additions = expected_additions - (match_index - new_index) self.new_index = match_index end
append_deletion(item, index)
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 143 def append_deletion(item, index) key = Hashdiff.prefix_append_array_index(options[:prefix], index, options) deletions << ['-', key, item] end
append_deletions_before_match(match_index)
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 130 def append_deletions_before_match(match_index) return unless match_index (old_index...match_index).each { |i| append_deletion(old_array[i], i) } self.expected_additions = expected_additions + (match_index - new_index) self.old_index = match_index end
append_differences(difference)
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 148 def append_differences(difference) differences.concat(difference) end
changes()
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 152 def changes # this algorithm only allows there to be additions or deletions # deletions are reverse so they don't change the index of earlier items differences + additions + deletions.reverse end
compare_at_index()
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 66 def compare_at_index difference = item_difference(old_array[old_index], new_array[new_index], old_index) return if difference.empty? index_after_additions = index_of_match_after_additions append_addititions_before_match(index_after_additions) index_after_deletions = index_of_match_after_deletions append_deletions_before_match(index_after_deletions) match = index_after_additions || index_after_deletions append_differences(difference) unless match end
extra_items_in_new_array?()
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 58 def extra_items_in_new_array? new_index < new_array.length && old_index >= old_array.length end
extra_items_in_old_array?()
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 54 def extra_items_in_old_array? old_index < old_array.length && new_index >= new_array.length end
index_of_match_after_additions()
click to toggle source
look ahead in the new array to see if the current item appears later thereby having new items added
# File lib/hashdiff/linear_compare_array.rb, line 88 def index_of_match_after_additions return unless expected_additions > 0 (1..expected_additions).each do |i| next_difference = item_difference( old_array[old_index], new_array[new_index + i], old_index ) return new_index + i if next_difference.empty? end nil end
index_of_match_after_deletions()
click to toggle source
look ahead in the old array to see if the current item appears later thereby having items removed
# File lib/hashdiff/linear_compare_array.rb, line 106 def index_of_match_after_deletions return unless expected_additions < 0 (1..(expected_additions.abs)).each do |i| next_difference = item_difference( old_array[old_index + i], new_array[new_index], old_index ) return old_index + i if next_difference.empty? end nil end
item_difference(old_item, new_item, item_index)
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 81 def item_difference(old_item, new_item, item_index) prefix = Hashdiff.prefix_append_array_index(options[:prefix], item_index, options) Hashdiff.diff(old_item, new_item, options.merge(prefix: prefix)) end
iterated_through_both_arrays?()
click to toggle source
# File lib/hashdiff/linear_compare_array.rb, line 62 def iterated_through_both_arrays? old_index >= old_array.length && new_index >= new_array.length end