0

I am doing some stuff in python, but I am not that used to it yet.

This is what I want the code to do (pseudocode):

if x in list or y in list but not x and y:
    #do-stuff

the first part is correct (if x in list or y in list) but I don't know what to write after that. The but not x and ypart.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
user3685412
  • 4,057
  • 3
  • 16
  • 16

4 Answers4

4

I'd probably go for using a set here instead...

if len({x, y}.intersection(your_list)) == 1:
    # do something

This has the advantage that it only needs to iterate once over your_list.

Example:

examples = [
    [1, 2, 3, 4, 5],
    [2, 3, 4, 5, 6],
    [100, 101, 102, 103, 104]
]

for example in examples:
    overlap = {1, 5}.intersection(example)
    print 'overlap is', overlap, 'with a length of', len(overlap)

# overlap is set([1, 5]) with a length of 2
# overlap is set([5]) with a length of 1
# overlap is set([]) with a length of 0
Jon Clements
  • 138,671
  • 33
  • 247
  • 280
1

With "but" spelled and and a pair of parentheses, you can use:

x_in_list = x in list
y_in_list = y in list
if (x_in_list or y_in_list) and not (x_in_list and y_in_list):
    ...

Or, as suggested by behzad.nouri, use xor:

if (x in list) ^ (y in list):
    ...

This is shorter, but possibly less understandable to a non-CS-savvy reader.

Community
  • 1
  • 1
user4815162342
  • 141,790
  • 18
  • 296
  • 355
1

Exclusive or means "one or the other, but not both" and maps perfectly in what you want to do:

if (x in list) ^ (y in list):
    ...

looks a bit weird because normally xor is only used for bitwise operations, but here works because Python will implicitly convert True and False to 1 and 0, making the operator work as expected in an if.

Note however that the parenthesis are necessary because the xor operator ^ has an higher precedence than in (it's most often used for bitwise math, so this choice is reasonable).

6502
  • 112,025
  • 15
  • 165
  • 265
  • 2
    Note that `True` and `False` aren't *converted* to 1 and 0, in a very real sense they [already *are*](http://stackoverflow.com/a/20756275/1600898) 1 and 0. – user4815162342 Jul 05 '14 at 12:33
1

Inspired by Jon Clements's centi-upvoted answer,

items, it = {x, y}, (i in items for i in lst)
print(any(it) and not any(it))

This short-circuit version is better, in the negative cases.

it is an iterator of the original list, and we check if any of it is in items, if yes we check if all the other items are not in items.

Note: This works only if the items are unique in lst

Community
  • 1
  • 1
thefourtheye
  • 233,700
  • 52
  • 457
  • 497