HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Python code for detecting a single item moved in a list

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
itemmovedsingleforpythoncodelistdetecting

Problem

I need to write a function that takes an original list of unique values and a resulting list:

[0,1,2,3]
[0,3,1,2]


and detect that only a single element was moved then report exactly what was moved where. If the resulting list is not the result of moving exactly one item from source to destination, this code should fail.

Here are some examples:

[0,1,2,3]
[0,3,1,2]


location 3 was moved to location 1

Failure cases (not exactly one move could be detected) include:

[4,1,2,3]
[1,3,1,2]


(before/after have different items)

[1,1,2,3]
[1,3,1,2]


(before has duplicate values)

[4,5,1,2,3]
[1,3,1,2]


(before/after not the same size)

My basic approach is to iterate both lists simultaneously until there's a difference. If the destination list has a different item, then we see if the next item matches the source lists current item. This indicates that something has been inserted at this point. We then move forward the destination list and proceed. We notice removals in a similar process. If the we've decided its not an insertion, that is two items are not equal but the source does NOT continue in the destination list, then we treat it as a removal.

In the case of an insertion, we only move the destination list forward. We expect the rest of the dest list/src list to match up until we detect a removal. In the case of detecting a removal, we move forward the source list. If both elements are equal, we move them both forward.

For example:

original: result:
1----------4 // not equal, peek ahead and compare 1==1, this is just an insertion
2--- \-----1 // 1 == 1 same
3-- \------2 // 2 == 2 same
4- \-------3 // 3 == 3 same
\-------- // result exhausted, removal




original: result:
1----\-----4 // not equal, peek ahead and compare 1==1, this is an insertion, move just result ahead 1
2--\ \----1 // 1 == 1 same
3-\ \------2 // 2 == 2 same
4\ \-------3 // 3 == 3 same
\-------- // result exhausted, removal




`original: result:
1-

Solution

This seems a shorter solution:

def findMove(original,result):
    if len(original) != len(result):
        return # different length                                               

    diff = [x for x,(c,d) in enumerate(zip(original,result)) if c!=d]
    if not diff:
        return # equal strings                                                  
    i,j = diff[0],diff[-1]

    if original[i+1:j+1] == result[i:j] and original[i] == result[j]:
        return (i,j)
    if original[i:j] == result[i+1:j+1] and original[j] == result[i]:
        return (j,i)


PS: this works also if the items are non unique.

Code Snippets

def findMove(original,result):
    if len(original) != len(result):
        return # different length                                               

    diff = [x for x,(c,d) in enumerate(zip(original,result)) if c!=d]
    if not diff:
        return # equal strings                                                  
    i,j = diff[0],diff[-1]

    if original[i+1:j+1] == result[i:j] and original[i] == result[j]:
        return (i,j)
    if original[i:j] == result[i+1:j+1] and original[j] == result[i]:
        return (j,i)

Context

StackExchange Code Review Q#61282, answer score: 4

Revisions (0)

No revisions yet.