1

I want to accomplish the following:

I have two lists a and b which are guaranteed to be of size 5. I now want to remove values from the end of both lists that are equal at the same indices / when zipped/transposed. As an example of input and expected output:

In:   a=[2,3,2,2,1], b=[2,3,4,1,1]
Out:  a=[2,3,2,2],   b=[2,3,4,1]

In:   a=[9,10,10,10,10], b=[10,10,10,10,10]
Out:  a=[9],             b=[10]

In:   a=[1,2,3,4,5], b=[1,2,3,4,5]
Out:  a=[],          b=[] 
# (a=[1], b=[1] or a=[1,2,3,4,5], b[1,2,3,4,5] are fine as well
#  for this last example, as long as there isn't any error)

In:  a=[10,10,10,10,10], b=[10,10,10,10,9]
Out: a=[10,10,10,10,10], b=[10,10,10,10,9]

I know how to remove all values that are equal at the same indices:

f = lambda a,b: [] if a==b else map(list, zip(*[(i,j) for(i,j) in zip(a,b) if i!=j]))[0]

Which I can then call as:

a,b = [2,3,2,2,1], [2,3,4,1,1]
A,B = f(a,b), f(b,a)

But this would result in A=[2,2], B=[4,1], also removing the leading values.

What would be the easiest approach to remove trailing values from both lists until a mismatch is found at the same index?
PS: This is for a code-golf challenge. I almost never program in Python, but if I would use it elsewhere I'd probably create variables for the zips instead of this quite unreadable single line I have above. Still, for this answer I would prefer as short as possible answers over readability, although it's not a requirement for this question. Just want to know how to accomplish it in general.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Kevin Cruijssen
  • 9,153
  • 9
  • 61
  • 135

3 Answers3

3

One approach is to use a generator expression to iterate over both lists starting from the end, and keep the first index where a match is found:

a=[2,3,2,2,1]
b=[2,3,4,1,1]

ix = next((ix for ix,(i,j) in enumerate(zip(a[::-1],b[::-1])) if i != j), None) 

Which you can then use to slice the lists (use an if statement to check if the returned values is None, which would mean that both lists are equal):

if ix:
    print(a[:len(a)-ix])
    print(b[:len(b)-ix])
# [2, 3, 2, 2]
# [2, 3, 4, 1]

And for your other example:

a=[9,10,10,10,10]
b=[10,10,10,10,10]

ix = next(ix for ix,(i,j) in enumerate(zip(a[::-1],b[::-1])) if i != j)

if ix:
    print(a[:len(a)-ix])
    print(b[:len(b)-ix])
# [9]
# [10]
yatu
  • 86,083
  • 12
  • 84
  • 139
  • Ah, that looks pretty good. Btw, isn't `i-j != 0` simply `i != j`? – Kevin Cruijssen Apr 30 '19 at 15:28
  • Hmm, this doesn't seem to work for `a=[10,10,10,10,10], b=[10,10,10,10,9]` (which would mean `a` and `b` remain the same, but their currently resulting in `[]` after the `a[:-ix]` and `b[:ix]`). Forgot about that test case.. Will add it to the question. What would be an easy fix for this? – Kevin Cruijssen Apr 30 '19 at 15:38
  • Yess true, it has to do with the final slicing. Added a quick fix @KevinCruijssen – yatu Apr 30 '19 at 15:39
  • 2
    also a `None` default value should be passed to `next` to avoid error when a == b – Lante Dellarovere Apr 30 '19 at 15:53
  • Was about to make a comment stating `a[len(a):-ix]` didn't work, but I see you've edited it to `a[:len(a)-ix]` which works like a charm. :) It only doesn't work if both `a` and `b` are completely equal, but that's easy to fix with `[] if a==b else `. Thanks! Will accept it as the answer. – Kevin Cruijssen Apr 30 '19 at 16:04
  • Yess I'm also updating to fix that, thanks fotr pointing out @LanteDellarovere – yatu Apr 30 '19 at 16:05
  • @yatu Ah, perfect. [Seems to work like a charm for all my test cases (after changing `None` to `0` for my use-case).](https://tio.run/##fY/BCoMwEETvfsX2loUVjK0HBb/Co@SQ0EgjNYpEsP35dEWQForswg7DvIGdXuEx@jzGpn7qwdw1aDKVbqsi9XYNQqzQjTOsJBz16DxYvwx21sGKt5sEB6tUKjL7RXQduEvdI2WokoS7oIZWZvS1in6MUiXT7HyARnAcqRGGNB5seYKyccpKyulKNyo27tCnyBbKefindgck639IjB8) :) Accepted, and thanks again! – Kevin Cruijssen Apr 30 '19 at 16:13
2
a=[2,3,2,2,1]
b=[2,3,4,1,1]

solution 1: use while loop

NOTE : Exception Handling (try-except block),to avoid :IndexError: list index out of range, in special cases like if you have a=[1,2,3,4,5], b=[1,2,3,4,5]

try: 
    while a[-1] == b[-1]:
            a.pop()
            b.pop()
except:
    pass
print (a)
print (b)

or

while a and a[-1] == b[-1]:
        a.pop()
        b.pop()

print (a)
print (b)

Result:

in: a=[2,3,2,2,1], b=[2,3,4,1,1]
out: [2, 3, 2, 2],[2, 3, 4, 1]

in: a=[10,10,10,10,10],b=[10,10,10,10,9]
out: [10, 10, 10, 10, 10],[10, 10, 10, 10, 9]

in: a=[9,10,10,10,10],b=[10,10,10,10,10]
out: [9],[10]

in: a=[1,2,3,4,5],b=[1,2,3,4,5]
out: [], []

solution 2: use recursion

def remove(a,b):
    if a[-1] == b[-1]:
        a.pop()
        b.pop()
        return remove(a,b)
    # else:
    #     return

remove(a,b)
print (a)
print (b)

Python slice()

The slice() constructor creates a slice object representing the set of indices specified by range(start, stop, step).

 a[-1] # return a last element of list

Python List pop()

The pop() method removes the item at the given index from the list. The method also returns the removed item.

The syntax of the pop() method is:

list.pop(index)

a.pop() # removing last element of list
ncica
  • 7,015
  • 1
  • 15
  • 37
0

You could iterate over a copy of the list thats is reversed from the original and then iterate over the copy and remove elements from the original like this function:

class SomeClass:

def removeSameCharacters(a, b):
    x = a.reverse
    y = b.reverse

    for i in x:
        if x[i] == y[i]:
            a.remove[i]
            b.remove[i]
        else:
            break