Reputation: 49
I am trying to understand why the in operator below does not also match and print (4, 'foobar'), and ('foobar', 5) (it matches the rest). Trying to nail down my understanding of the in with tuples. I was trying to match all tuples that had "foo" or "bar", or "foobar" in any part of the tuple.
ls = [(1, 'foo'), ('bar2'), ('foo', 'bar', 3), (4, 'foobar'), ('foobar', 5), ('foobar')]
print [x for x in ls if 'foo' in x or 'bar' in x]
[(1, 'foo'), 'bar2', ('foo', 'bar', 3), 'foobar']
Upvotes: 2
Views: 198
Reputation: 114478
For a tuple, 'foo' in x
means "is there an element of x
that equals 'foo'
", not "is there an element of x
that contains 'foo'
".
To do the latter, you could do something like
any('foo' in y for y in x)
However, for a string, 'foo' in x
means "is 'foo'
a substring of x
".
Additionally, a single element in parentheses (e.g. ('bar2')
and ('foobar')
) does not make a tuple. To make a tuple, you generally need a comma in the parentheses: ('bar2',)
and ('foobar',)
. Both of these elements match because they are not tuples and contain the right substring.
If you are looking specifically for foo
, bar
and foobar
, not something like barfoo
, just add an additional or
to the comprehension:
[x for x in ls if 'foo' in x or 'bar' in x or 'foobar' in x]
You could generalize using any
by doing something like
search_terms = ('foo', 'bar', 'foobar')
[x for x in ls if any(a in x for a in search_terms)]
Upvotes: 3
Reputation: 5354
Because ('bar2') is not a tuple, but just the string 'bar2' (and 'bar' is in that string), while ('foobar', 1) is a tuple and 'bar' is not one of ('foobar', 1).
'in' works differently on a list/tuple and on a single string. When applied to a string, it asks "is 'foo' a substring?". When applied to a list/tuple, it asks "is 'foo' equal to one of the list/tuple items?".
Upvotes: 2