By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
464,384 Members | 1,081 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 464,384 IT Pros & Developers. It's quick & easy.

newbie question: for loop within for loop confusion

P: n/a
Hi,

I'm studying python via the exellent book "How to think like a python
programmer" by Allen Downey.

Noob question follows...

animals.txt is a list of animals, each on a separate line: "aardvard,
bat, cat, dog, elephant, fish, giraffe, horse, insect, jackelope"

I want to loop through the list of words and print words that don't
have any "avoid" letter in them.

def hasnolet(avoid):
fin = open('animals.txt')
for line in fin:
word = line.strip()
for letter in avoid:
if letter in word:
break
else:
print word

hasnolet('abcd')

Why doesn't the function above work? It returns:

dog
dog
dog
fish
fish
fish
fish
horse
horse
horse
horse
inchworm
inchworm
thanks for any help.

takayuki
Jun 27 '08 #1
Share this Question
Share on Google+
17 Replies

P: n/a
In article
<a0**********************************@g16g2000pri. googlegroups.com>,
takayuki <la********@gmail.comwrote:
Hi,

I'm studying python via the exellent book "How to think like a python
programmer" by Allen Downey.

Noob question follows...

animals.txt is a list of animals, each on a separate line: "aardvard,
bat, cat, dog, elephant, fish, giraffe, horse, insect, jackelope"

I want to loop through the list of words and print words that don't
have any "avoid" letter in them.

def hasnolet(avoid):
fin = open('animals.txt')
for line in fin:
word = line.strip()
for letter in avoid:
if letter in word:
break
else:
print word

hasnolet('abcd')
I could give you a fish, or I could teach you to fish. I'd rather do the
latter. So...

Take your inner loop:
for letter in avoid:
if letter in word:
break
else:
print word
and instrument it so you can see exactly what's happening. Try something
like:
for letter in avoid:
print "letter = %s" % letter
if letter in word:
print "it's in word"
break
else:
print "no it's not"
print word
and see if that helps.
Jun 27 '08 #2

P: n/a
On 09:23, lunedì 16 giugno 2008 takayuki wrote:
word = line.strip()
Try
word= line.split()

and at the end of the loop add one more print to go to new line.
--
Mailsweeper Home : http://it.geocities.com/call_me_not_now/index.html
Jun 27 '08 #3

P: n/a
takayuki wrote:

for letter in avoid:
if letter in word:
break
else:
print word
Take the word 'dog', for example. What the above loop is doing is
basically this:

1. for letter in avoid uses 'a' first
2. is 'a' in 'dog'?
3. no, so it prints 'dog'
4. go back to for loop, use 'b'
5. is 'b' in 'dog'?
6. no, so it prints 'dog' again
7. go back to for loop.....

Since it goes sequentially through 'abcd', it will say that the first
three letters are not in 'dog', and therefore print it three times. Then
it finally sees that 'd' *is* in dog, so it skips it the fourth time
through the loop.
Jun 27 '08 #4

P: n/a
takayuki wrote:
inchworm
inchworm
P.S. Why does 'inchworm' only print twice? Or is that not the full output?
Jun 27 '08 #5

P: n/a
Thanks to everyone for the excellent advice.

Roy: I did as you suggested and could see after staring at the output
for awhile what was going on. The print statements really helped to
put a little light on things. Yes, I agree that "learning to fish" is
the best way.

John: There were two "inchworms" because "c" is in "inchworm" so it
shouldn't print. Thanks for your detailed description of the for
loop.

The Saint: i'll check out the word = line.split() command.
After much flailing about, here's a loop that is working:

def hasnolet2(avoid):
fin = open('animals.txt')
for line in fin:
word = line.strip()

length = len(avoid)
x = 0
noprint = 0

while length -1 >= x:
if avoid[x] in word:
noprint = noprint + 1
x = x + 1

if noprint == 0:
print word

hasnolet2('abcd')

which should return:
fish
horse
hasnolet2('abcd')
Jun 27 '08 #6

P: n/a
On Jun 16, 2:35*pm, takayuki <lawtonp...@gmail.comwrote:
def hasnolet2(avoid):
* * * * fin = open('animals.txt')
* * * * for line in fin:
* * * * * * * * word = line.strip()

* * * * length = len(avoid)
* * * * x = 0
* * * * noprint = 0

* * * * while length -1 >= x:
* * * * * * * * if avoid[x] in word:
* * * * * * * * * * * * noprint = noprint + 1
* * * * * * * * x = x + 1

* * * * if noprint == 0:
* * * * * * * * print word
There seems to be an indendation problem (presumably the code from
length = len(avoid) onwards should be inside the loop). But apart from
that, we can try to make this more 'pythonic'.

First, python has a 'for' statement that's usually better than using
while. We use the 'range' function that produces the numbers 0, 1, ...
length - 1, and x takes the value of these in turn.

Here's the last bit of your code rewritten like this:

noprint = 0

for x in range(length):
if avoid[x] in word:
noprint += 1

if noprint == 0:
print word

But better, rather than using 'x' as an index, we can loop over
letters in avoid directly. I've changed 'noprint' to be a boolean
'should_print' too here.

should_print = True
for letter in avoid:
if letter in word:
should_print = False

if should_print:
print word

We can eliminate 'should_print' completely, by using 'break' and
'else'. A break statement in a loop causes the loop to end. If the
loop doesn't break, the 'else' code is run when the loop's over.

for letter in avoid:
if letter in word:
break
else:
print word

This is almost the same as your original code, but the 'else' is
attached to the 'for' rather that the 'if'!

Finally, in Python 2.5 you can write this:

if not any(letter in word for letter in avoid):
print word

I think this is the best solution, as it's readable and short.

--
Paul Hankin
Jun 27 '08 #7

P: n/a
"takayuki" <la********@gmail.comwrote in message
news:ba**********************************@g16g2000 pri.googlegroups.com...
John: There were two "inchworms" because "c" is in "inchworm" so it
shouldn't print. Thanks for your detailed description of the for
loop.
lol, I even sat there looking at the word and said to myself "ok, it doesn't
contain any of the four letters" :)
Jun 27 '08 #8

P: n/a
"takayuki" <la********@gmail.comwrote in message
news:a0**********************************@g16g2000 pri.googlegroups.com...
fin = open('animals.txt')
for line in fin:
You can write this as:

for line in open('animals.txt'):
#do stuff

Of course, you can't explicitly close the file this way, but that probably
doesn't matter. Another way, I think, is to wrap the for loops in this:

with open('animals.txt') as file:
#for loop stuff here
Jun 27 '08 #9

P: n/a
On Jun 16, 7:17 am, Paul Hankin <paul.han...@gmail.comwrote:
On Jun 16, 2:35 pm, takayuki <lawtonp...@gmail.comwrote:
def hasnolet2(avoid):
fin = open('animals.txt')
for line in fin:
word = line.strip()
length = len(avoid)
x = 0
noprint = 0
while length -1 >= x:
if avoid[x] in word:
noprint = noprint + 1
x = x + 1
if noprint == 0:
print word

There seems to be an indendation problem (presumably the code from
length = len(avoid) onwards should be inside the loop). But apart from
that, we can try to make this more 'pythonic'.

First, python has a 'for' statement that's usually better than using
while. We use the 'range' function that produces the numbers 0, 1, ...
length - 1, and x takes the value of these in turn.

Here's the last bit of your code rewritten like this:

noprint = 0

for x in range(length):
if avoid[x] in word:
noprint += 1

if noprint == 0:
print word

But better, rather than using 'x' as an index, we can loop over
letters in avoid directly. I've changed 'noprint' to be a boolean
'should_print' too here.

should_print = True
for letter in avoid:
if letter in word:
should_print = False

if should_print:
print word

We can eliminate 'should_print' completely, by using 'break' and
'else'. A break statement in a loop causes the loop to end. If the
loop doesn't break, the 'else' code is run when the loop's over.

for letter in avoid:
if letter in word:
break
else:
print word

This is almost the same as your original code, but the 'else' is
attached to the 'for' rather that the 'if'!

Finally, in Python 2.5 you can write this:

if not any(letter in word for letter in avoid):
print word

I think this is the best solution, as it's readable and short.
Alternatively, you could use sets:

if not(set(word) & set(avoid)):
print word

(parentheses added for clarity.)
Jun 27 '08 #10

P: n/a
On Jun 15, 6:23 pm, takayuki <lawtonp...@gmail.comwrote:
def hasnolet(avoid):
fin = open('animals.txt')
for line in fin:
word = line.strip()
for letter in avoid:
if letter in word:
break
else:
print word
You're using the split command correctly, but you're not filtering
correctly. Consider this:

---begin---
fin = open('animals.txt')
"\n".join(["%s" % line for line in fin if len(line.strip('abcd')) ==
len(line)])
----end----

Let's go slow.

"\n".join([...])

1. Take everything that is in the following list, and print each one
with a carriage return appended to it.

"\n".join(["%s" % line for line in fin ...])

2. For each line in fin, create a string that only consists of what
currently in the line variable, using string substitution.

"\n".join(["%s" % line for line in fin if len(line.strip('abcd')) ==
len(line)])

3. Only do #2 if the length of the line after stripping out the
unnecessary characters is the same length as the line originally. This
way we filter out the lines we don't want. If we wanted the lines that
have been filtered, we can change "==" to "!=" or "<=".

Now, I read "Dive Into Python" first, which through these early on in
the book. If your eyes cross looking at this, write it down and read
it again after you get a little farther into the book you're reading
Jun 27 '08 #11

P: n/a
On Jun 16, 2:34 pm, Thomas Hill <tomlikestor...@gmail.comwrote:
On Jun 15, 6:23 pm, takayuki <lawtonp...@gmail.comwrote:
def hasnolet(avoid):
fin = open('animals.txt')
for line in fin:
word = line.strip()
for letter in avoid:
if letter in word:
break
else:
print word

You're using the split command correctly, but you're not filtering
correctly. Consider this:

---begin---
fin = open('animals.txt')
"\n".join(["%s" % line for line in fin if len(line.strip('abcd')) ==
len(line)])
----end----

Let's go slow.

"\n".join([...])

1. Take everything that is in the following list, and print each one
with a carriage return appended to it.

"\n".join(["%s" % line for line in fin ...])

2. For each line in fin, create a string that only consists of what
currently in the line variable, using string substitution.

"\n".join(["%s" % line for line in fin if len(line.strip('abcd')) ==
len(line)])

3. Only do #2 if the length of the line after stripping out the
unnecessary characters is the same length as the line originally. This
way we filter out the lines we don't want. If we wanted the lines that
have been filtered, we can change "==" to "!=" or "<=".

Now, I read "Dive Into Python" first, which through these early on in
the book. If your eyes cross looking at this, write it down and read
it again after you get a little farther into the book you're reading
Guh, no, I'm reading the description of strip wrong. Fooey. Anyone
else able to one line it?
Jun 27 '08 #12

P: n/a
Paul,

Thank you for the informative reply.

Yes, I created the indent problem when manually copying the original
script when I posted. (I'm using an old laptop to study python and
posting here using the desktop.)

Your examples really helped. Last night I played with using a for
loop instead of a while loop and got it working, but your examples
really clarified things.

This loop was particularly interesting because I didn't know the else
could be attached to the for. Attaching it to the for solved a lot of
problems.

for letter in avoid:
if letter in word:
break
else:
print word
I've printed out this whole thread and will be playing with your and
others' solutions.

I love this one for its conciseness, but will have to play with it to
get my head around it.

if not any(letter in word for letter in avoid):
print word

Thanks again.

takayuki
Jun 27 '08 #13

P: n/a
On Jun 17, 6:34 am, Thomas Hill <tomlikestor...@gmail.comwrote:
On Jun 15, 6:23 pm, takayuki <lawtonp...@gmail.comwrote:
def hasnolet(avoid):
fin = open('animals.txt')
for line in fin:
word = line.strip()
for letter in avoid:
if letter in word:
break
else:
print word

You're using the split command correctly, but you're not filtering
correctly. Consider this:

---begin---
fin = open('animals.txt')
"\n".join(["%s" % line for line in fin if len(line.strip('abcd')) ==
len(line)])
----end----

Let's go slow.

"\n".join([...])

1. Take everything that is in the following list, and print each one
with a carriage return appended to it.

"\n".join(["%s" % line for line in fin ...])

2. For each line in fin, create a string that only consists of what
currently in the line variable, using string substitution.

"\n".join(["%s" % line for line in fin if len(line.strip('abcd')) ==
len(line)])

3. Only do #2 if the length of the line after stripping out the
unnecessary characters is the same length as the line originally. This
way we filter out the lines we don't want. If we wanted the lines that
have been filtered, we can change "==" to "!=" or "<=".

Now, I read "Dive Into Python" first, which through these early on in
the book. If your eyes cross looking at this, write it down and read
it again after you get a little farther into the book you're reading
Thomas,

thanks for the reply.

I'm early on in my python adventure so I'm not there yet on the strip
command nuances. I'm reading "How to think like a python
programmer" first. It's great.

Then "Learning python". I've read parts of Dive into Python and will
work through it fully when I'm a little farther along.

takayuki
Jun 27 '08 #14

P: n/a
takayuki wrote:
I'm early on in my python adventure so I'm not there yet on the strip
command nuances. I'm reading "How to think like a python
programmer" first. It's great.

Then "Learning python". I've read parts of Dive into Python and will
work through it fully when I'm a little farther along.
Yeah, I really recommend Learning Python for getting the basics first.
It's very thorough in that regard. Dive Into Python is *not* for
beginners. I'm sorry if people disagree, but it's just not.
Jun 27 '08 #15

P: n/a
takayuki wrote:
Paul,

Thank you for the informative reply.

Yes, I created the indent problem when manually copying the original
script when I posted. (I'm using an old laptop to study python and
posting here using the desktop.)

Your examples really helped. Last night I played with using a for
loop instead of a while loop and got it working, but your examples
really clarified things.

This loop was particularly interesting because I didn't know the else
could be attached to the for. Attaching it to the for solved a lot of
problems.

for letter in avoid:
if letter in word:
break
else:
print word
I've printed out this whole thread and will be playing with your and
others' solutions.

I love this one for its conciseness, but will have to play with it to
get my head around it.

if not any(letter in word for letter in avoid):
print word

Thanks again.

takayuki
--
http://mail.python.org/mailman/listinfo/python-list
takayuki,

Could you post the complete script.
thanks
david
--
Powered by Gentoo GNU/LINUX
http://www.linuxcrazy.com

Jun 27 '08 #16

P: n/a
En Mon, 16 Jun 2008 22:51:30 -0300, John Salerno <jo******@gmailNOSPAM.comescribió:
takayuki wrote:
>I'm early on in my python adventure so I'm not there yet on the strip
command nuances. I'm reading "How to think like a python
programmer" first. It's great.

Then "Learning python". I've read parts of Dive into Python and will
work through it fully when I'm a little farther along.

Yeah, I really recommend Learning Python for getting the basics first.
It's very thorough in that regard. Dive Into Python is *not* for
beginners. I'm sorry if people disagree, but it's just not.
Sure, the author himself says so at the very beginning in http://www.diveintopython.org "Dive Into Python is a Python book for experienced programmers."

--
Gabriel Genellina

Jun 27 '08 #17

P: n/a
Gabriel Genellina wrote:
En Mon, 16 Jun 2008 22:51:30 -0300, John Salerno <jo******@gmailNOSPAM.comescribió:
>takayuki wrote:
>>I'm early on in my python adventure so I'm not there yet on the strip
command nuances. I'm reading "How to think like a python
programmer" first. It's great.

Then "Learning python". I've read parts of Dive into Python and will
work through it fully when I'm a little farther along.
Yeah, I really recommend Learning Python for getting the basics first.
It's very thorough in that regard. Dive Into Python is *not* for
beginners. I'm sorry if people disagree, but it's just not.

Sure, the author himself says so at the very beginning in http://www.diveintopython.org "Dive Into Python is a Python book for experienced programmers."
I know, but I just hear so many people recommend that book for people
who want to learn the language.
Jun 27 '08 #18

This discussion thread is closed

Replies have been disabled for this discussion.