3

I have two n-length tuples and I need to check whether all the elements in the same position are the same except for the element in position w. This is what I wrote:

if all(tup1[i] == tup2[i] for i in xrange(n) if i != w):
    ...

In order to avoid the loop (since this piece of code will be used many times), I tried to use slicing. Unfortunately, this doesn't work:

if tup1[w-1:w-n:-1] == tup2[w-1:w-n:-1]:
    ...

Am I obliged to write something like this?

if tup1[:w-1] == tup2[:w-1] and tup1[w+1:] == tup2[w+1:]

Isn't there a more elegant methodd?

Or both loop and slicing are no good and there is a better way of obtaining the result I'm looking for? (I can't use filter because there may be elements with the same value of the one in position w)

Pigna
  • 2,792
  • 5
  • 29
  • 51
  • 7
    `all` method will be better because, when you slice the tuples you will be creating copies of the original tuples by iterating them. But when you use `all`, if two elements are different, rest of the tuple will not be iterated at all. – thefourtheye Dec 24 '15 at 11:12
  • 3
    This is definitely a case of **premature optimization**. You are trying to iterate through n-1 items (negligible optimization) at the expense of copying the whole lists each time! Do not optimize until profiling tells you that there is a problem. – zvone Dec 24 '15 at 11:13
  • Indeed, there this is not even a nested loop. The complexity required to equalize two iterables and do a for loop check is both linear. Therefore optimization non-required. – Rockybilly Dec 24 '15 at 11:17

1 Answers1

0

I think you've already found the best solution:

 tup1[:w-1] == tup2[:w-1] and tup1[w+1:] == tup2[w+1:]

If the tuples were extremly long and you didn't want to copy the data and you wanted early-out behavior, there is a much more complicated alternative using itertools and operator:

>>> from operator import eq
>>> from itertools import imap
>>> w = 5
>>> t1 = (10, 20, 30, 40, -1, 50, 60, 70)
>>> t2 = (10, 20, 30, 40, -1, 50, 60, 70)
>>> it1, it2 = iter(t1), iter(t2)
>>> all(imap(eq, islice(it1, w-1), islice(it2, w-1))) \
    and (next(it1, True) or True) and (next(it2, True) and True) \
    and all(imap(eq, it1, it2))
True

This is a lot of set-up work and stepwise isn't as fast as tuple slicing, but it does avoid copying all the data and it does have an early out.

In the non-extreme case, I would stick with your double-sliced-tuple-equality solution.

Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485