Created
September 11, 2024 06:56
-
-
Save StevenJL/32469f4aed8b5e5b5cd4edea82999fca to your computer and use it in GitHub Desktop.
find_moved_element
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 characters
# Algorithm to detect delete/insertion change (ie. drag-n-drop) in array of unique elements | |
# From https://webshittery.com/blog/cumbersome-apis/ | |
# Note that in certain situations where there is more than one correct answer | |
# For example: | |
# | |
# find_moved_element([1, 2, 3, 4, 5], [1, 3, 2, 4, 5]), | |
# | |
# Correct answers include: | |
# | |
# { moved_element: 3, original_index: 2, new_index: 1 } | |
# { moved_element: 2, original_index: 1, new_index: 2 } | |
# | |
# Another example: | |
# find_moved_element([1, 2, 3, 4, 5], [2, 3, 4, 5, 1]), | |
# | |
# Only one correct answer: | |
# { moved_element: 1, original_index: 0, new_index: 4 } | |
# N.B. "moved" is defined as deleting element, then inserting element back (think of drag-n-drop). | |
def find_moved_element(array_orig, array_moved) | |
if array_orig == array_moved | |
raise 'You didnt move anything, doofus!' | |
end | |
orig_index_hash = {} | |
array_orig.each do |el| | |
orig_index_hash[el] = array_orig.index(el) | |
end | |
moved_index_hash = {} | |
array_moved.each do |el| | |
moved_index_hash[el] = array_moved.index(el) | |
end | |
changed_value = nil | |
# Let's find the changed value! | |
array_orig.each do |el| | |
# Same index, means its unmoved | |
next if moved_index_hash[el] == orig_index_hash[el] | |
# Most of the time an absolute value difference of exactly 1 | |
# means this also wasn't the changed value. There are edge-cases so lets | |
# handle that below. | |
next if (moved_index_hash[el] - orig_index_hash[el]).abs == 1 | |
changed_value = el | |
break | |
end | |
# The edgecase occurred where the deleted element | |
# was then inserted exactly one away from its original position. | |
# In which case, any element that has a different index than | |
# before was the one that was moved. | |
unless changed_value | |
array_orig.each do |el| | |
# Same index, means its unmoved | |
next if moved_index_hash[el] == orig_index_hash[el] | |
changed_value = el | |
break | |
end | |
end | |
original_index = array_orig.index(changed_value) | |
new_index = array_moved.index(changed_value) | |
{ | |
moved_element: changed_value, | |
original_index: original_index, | |
new_index: new_index, | |
} | |
end | |
# TEST CASES | |
a = [1, 2, 3, 4, 5, 6, 7] | |
b = [1, 3, 2, 4, 5, 6, 7] | |
answer = find_moved_element(a, b) | |
unless answer == { moved_element: 2, original_index: 1, new_index: 2 } | |
raise "You dun goofed, doofus for #{b}" | |
end | |
a = [1, 2, 3, 4, 5, 6, 7] | |
b = [2, 3, 4, 5, 1, 6, 7] | |
answer = find_moved_element(a, b) | |
unless answer == { moved_element: 1, original_index: 0, new_index: 4 } | |
raise "You dun goofed, doofus for #{b}" | |
end | |
a = [1, 2, 3, 4, 5, 6, 7] | |
b = [7, 1, 2, 3, 4, 5, 6] | |
answer = find_moved_element(a, b) | |
unless answer == { moved_element: 7, original_index: 6, new_index: 0 } | |
raise "You dun goofed, doofus for #{b}" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment