searching for strings (in a tuple) in a string

M

manstey

Hi,

I often use:

a='yy'
tup=('x','yy','asd')
if a in tup:
<...>

but I can't find an equivalent code for:

a='xfsdfyysd asd x'
tup=('x','yy','asd')
if tup in a:
< ...>

I can only do:

if 'x' in a or 'yy' in a or 'asd' in a:
<...>

but then I can't make the if clause dependent on changing value of tup.

Is there a way around this?
 
F

Fredrik Lundh

manstey said:
but I can't find an equivalent code for:

a='xfsdfyysd asd x'
tup=('x','yy','asd')
if tup in a:
< ...>

I can only do:

if 'x' in a or 'yy' in a or 'asd' in a:
<...>

but then I can't make the if clause dependent on changing value of tup.

Is there a way around this?

is the "def" statement broken in your Python version ?

def findany(text, words):
for w in words:
if w in text:
return True
return False

if findany(a, tup):
...

</F>
 
W

wittempj

You can get the matching elements with a list comprehension with
something like

py> a='xfsdfyysd asd x'
py> tup=('x','yy','asd')
py> [x for x in tup if x in a.split()]
['x', 'asd']

Hope this helps
 
F

Fredrik Lundh

manstey said:
I know I can do it this way. I wanted to know if there was another way.

if you don't want to write Python programs, why are you using Python ?

</F>
 
S

Simon Forman

manstey said:
Hi,

I often use:

a='yy'
tup=('x','yy','asd')
if a in tup:
<...>

but I can't find an equivalent code for:

a='xfsdfyysd asd x'
tup=('x','yy','asd')
if tup in a:
< ...>

I can only do:

if 'x' in a or 'yy' in a or 'asd' in a:
<...>

but then I can't make the if clause dependent on changing value of tup.

Is there a way around this?

One thing I do sometimes is to check for True in a generator
comprehension

if True in (t in a for t in tup):
# do whatever here


Because you're using a generator you get the same "short-circut"
behavior that you would with a series of 'or's, the if statement won't
bother checking the rest of the terms in tup after the first True
value.
print n
return n > m
print 'done'


0
1
2
3
done

# See? No 4! :)


I usually use this with assert statements when I need to check a
sequence. Rather than:

for something in something_else: assert expression

I say

assert False not in (expression for something in something_else)

This way the whole assert statement will be removed if you use the '-O'
switch to the python interpreter. (It just occurred to me that that's
just an assumption on my part. I don't know for sure that the
interpreter isn't smart enough to remove the first form as well. I
should check that. ;P )

Note, in python 2.5 you could just say

if any(t in a for t in tup):
# do whatever here


In your case though, if I were doing this kind of thing a lot, I would
use a little helper function like the findany() function Fredrik Lundh
posted.

IMHO

if findany(a, tup):
...

is much clearer and readily understandable than mucking about with
generator comprehensions...


Peace,
~Simon
 
S

Steven D'Aprano

Hi,

I often use:

a='yy'
tup=('x','yy','asd')
if a in tup:
<...>

but I can't find an equivalent code for:

a='xfsdfyysd asd x'
tup=('x','yy','asd')
if tup in a:
< ...>

Of course you can't. Strings don't contain tuples, since they are utterly
different kinds of objects.
I can only do:

if 'x' in a or 'yy' in a or 'asd' in a:
<...>

but then I can't make the if clause dependent on changing value of tup.

Sure you can.

a = 'xfsdfyysd asd x'
tup = ('x','yy','asd')
for item in tup:
if item not in a:
print "Item missing"
break
else:
print "All items found."

It's a little verbose, but you can stick it into a function definition and
use it as a one-liner.

Or, use a list comprehension:

a = 'xfsdfyysd asd x'
tup = ('x','yy','asd')
if [item for item in tup if item in a]:
print "Some items found."
else:
print "No items found."

Or, you can use filter:

a = 'xfsdfyysd asd x'
tup = ('x','yy','asd')
if filter(lambda item, a=a: item in a, tup):
print "Some items found."
else:
print "No items found."


However, keep in mind that "in" has a subtly different effect in strings
and tuples.

"x" in ("x", "y") is true, but "x" in ("xy", "yy") is not, as you would
expect. However, the situation for strings isn't quite the same:
"x" in "x y" is true, but so is "x" in "xx yy".

One way around that is to convert your string a into a list:

a = 'xfsdfyysd asd x'
a = a.split() # split on any whitespace

and now your tests will behave as you expected.
 
S

Simon Forman

Simon Forman wrote:
....
I usually use this with assert statements when I need to check a
sequence. Rather than:

for something in something_else: assert expression

I say

assert False not in (expression for something in something_else)

This way the whole assert statement will be removed if you use the '-O'
switch to the python interpreter. (It just occurred to me that that's
just an assumption on my part. I don't know for sure that the
interpreter isn't smart enough to remove the first form as well. I
should check that. ;P )

FWIW I did just check that and it seems valid, the second form gets
"optimized" away.

File delme.py:
import dis

N = (True, True, False)

def a():
for n in N:
assert n

def b():
assert False not in (n for n in N)

dis.dis(a)
print '==============================='
dis.dis(b)


Results of running it without '-O':
$ python delme.py
8 0 SETUP_LOOP 28 (to 31)
3 LOAD_GLOBAL 0 (N)
6 GET_ITER 10 STORE_FAST 0 (n)

9 13 LOAD_FAST 0 (n)
16 JUMP_IF_TRUE 7 (to 26)
19 POP_TOP
20 LOAD_GLOBAL 2 (AssertionError)
23 RAISE_VARARGS 1 34 RETURN_VALUE
===============================
13 0 LOAD_GLOBAL 0 (False)
3 LOAD_CONST 1 (<code object <generator
expression> at 0xb7d89ca0, file "delme.py", line 13>)
6 MAKE_FUNCTION 0
9 LOAD_GLOBAL 1 (N)
12 GET_ITER
13 CALL_FUNCTION 1
16 COMPARE_OP 7 (not in)
19 JUMP_IF_TRUE 7 (to 29)
22 POP_TOP
23 LOAD_GLOBAL 2 (AssertionError)
26 RAISE_VARARGS 1 30 LOAD_CONST 0 (None)
33 RETURN_VALUE


Results of running it with '-O':
$ python -O delme.py
8 0 SETUP_LOOP 14 (to 17)
3 LOAD_GLOBAL 0 (N)
6 GET_ITER 10 STORE_FAST 0 (n)

9 13 JUMP_ABSOLUTE 7 20 RETURN_VALUE
===============================
13 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,765
Messages
2,569,568
Members
45,042
Latest member
icassiem

Latest Threads

Top