app/utils/array_utils.rb
# ArrayUtils.diff_by_key(
# [{id: 1, value: :a}, {id: 2, value: :b}],
# [{id: 2, value: :d}, {id: 3, value: :c}])
# =>
# [
#   {action: :removed, value: {id: 1, value: :a}},
#   {action: :changed, value: {id: 2, value: :d}},
#   {action: :added, value {id: 3, value: :d}}
# ]
#
# Element without key is always considered as new addition
#


Element without key is always considered as new addition
Element without key is always considered as new addition
def diff_by_key(old_array, new_array, key)
    operations = []
    new_without_key, new_with_key = new_array.partition { |new| new[key].nil? }
    old_elems = old_array.sort_by { |old| old[key] }
    new_elems = new_with_key.sort_by { |new| new[key] }
    until old_elems.empty? || new_elems.empty?
      old = old_elems.first
      new = new_elems.first
      case old[key] <=> new[key]
      when -1
        operations << {action: :removed, value: old}
        old_elems.shift
      when 0
        if old == new
        else
          operations << {action: :changed, value: new}
        end
        old_elems.shift
        new_elems.shift
      when 1
        operations << {action: :added, value: new}
        new_elems.shift
      end
    end
    old_elems.each { |old| operations << {action: :removed, value: old}}
    new_elems.each { |new| operations << {action: :added, value: new}}
    new_without_key.each { |new| operations << {action: :added, value: new}}
    operations
  end
def diff_by_key ( old_array , new_array , key ) operations = [ ] new_without_key , new_with_key = new_array . partition { | new | new [ key ] . nil? } old_elems = old_array . sort_by { | old | old [ key ] } new_elems = new_with_key . sort_by { | new | new [ key ] } until old_elems . empty? || new_elems . empty? old = old_elems . first new = new_elems . first case old [ key ] <=> new [ key ] when - 1 operations << { action : :removed , value : old } old_elems . shift when 0 if old == new else operations << { action : :changed , value : new } end old_elems . shift new_elems . shift when 1 operations << { action : :added , value : new } new_elems . shift end end old_elems . each { | old | operations << { action : :removed , value : old } } new_elems . each { | new | operations << { action : :added , value : new } } new_without_key . each { | new | operations << { action : :added , value : new } } operations end
ArrayUtils.diff_by_key(
[{id: 1, value: :a}, {id: 2, value: :b}],
[{id: 2, value: :d}, {id: 3, value: :c}])
>
[
{action: :removed, value: {id: 1, value: :a}},
{action: :changed, value: {id: 2, value: :d}},
{action: :added, value {id: 3, value: :d}}
]
ArrayUtils . diff_by_key ( [ { id : 1 value : : a } { id : 2 value : : b } ] [ { id : 2 value : : d } { id : 3 value : : c } ] ) > [ { action : : removed value : { id : 1 value : : a }} { action : : changed value : { id : 2 value : : d }} { action : : added value { id : 3 value : : d }} ]
# Traverse sorted old and new arrays # remove # no change # update # add # See if there's still left something to process in old or new array # Element without key is always considered as new addition
old_array
new_array
key