[Tutor] trouble with list.remove() loop

2010-09-28 Thread D Ryan (2)
Hello all,
I am currently trying to write a program which can find the solution to a
game of hangman.
In a part of the program, a user inputs a letter, a tester tells him if
the word contains that letter, and then if the answer is no, all words
containing that letter are removed from the list of remaining candidates.
However, the code I've written seems to remove some, but not all the words
containing the letter. Strangely though, if i run it a few more times it
gets some of the ones it missed the 1st time round, untill after enough
iterations it gets all of them. I cant understand why it doesnt remove all
of them the first time round. I have cut the offending code and formatted
it to work on its own, and also to fit into a relatively short email.

# A sample list of words, one of which is the answer.
candidates = [abacus,amazing,
  ozimandias,
  a,alphanumeric,
  functioning]

# In the following code, the user has guessed the letter 'a',
# and the tester has told him that the letter 'a' is not in the word.

user_guess=a
tester_response=no

# The following code should eliminate all words which contain the letter
# 'a', leaving only the word 'functioning' in the list

if tester_response in (No,no,n,N,NO):
for word in candidates:
if user_guess in word:
print word, removed..
candidates.remove(word)
print candidates

Running once gives this output

abacus removed..
ozimandias removed..
alphanumeric removed..
['amazing', 'a', 'functioning']

But if i run it again it successfully removes 'amazing, and the next time
it removes 'a', leaving the correct answer. I'm perplexed by this strange
behaviour and would be most appreciative of any help. I'm very new to
python so apologies for any formatting/style errors, and also for the
simplicity of the problem.

Best regards
Dave

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] trouble with list.remove() loop

2010-09-28 Thread Christian Witts

On 25/09/2010 20:44, D Ryan (2) wrote:

Hello all,
I am currently trying to write a program which can find the solution to a
game of hangman.
In a part of the program, a user inputs a letter, a tester tells him if
the word contains that letter, and then if the answer is no, all words
containing that letter are removed from the list of remaining candidates.
However, the code I've written seems to remove some, but not all the words
containing the letter. Strangely though, if i run it a few more times it
gets some of the ones it missed the 1st time round, untill after enough
iterations it gets all of them. I cant understand why it doesnt remove all
of them the first time round. I have cut the offending code and formatted
it to work on its own, and also to fit into a relatively short email.

# A sample list of words, one of which is the answer.
candidates = [abacus,amazing,
   ozimandias,
   a,alphanumeric,
   functioning]

# In the following code, the user has guessed the letter 'a',
# and the tester has told him that the letter 'a' is not in the word.

user_guess=a
tester_response=no

# The following code should eliminate all words which contain the letter
# 'a', leaving only the word 'functioning' in the list

if tester_response in (No,no,n,N,NO):
 for word in candidates:
 if user_guess in word:
 print word, removed..
 candidates.remove(word)
print candidates

Running once gives this output

abacus removed..
ozimandias removed..
alphanumeric removed..
['amazing', 'a', 'functioning']

But if i run it again it successfully removes 'amazing, and the next time
it removes 'a', leaving the correct answer. I'm perplexed by this strange
behaviour and would be most appreciative of any help. I'm very new to
python so apologies for any formatting/style errors, and also for the
simplicity of the problem.

Best regards
Dave

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

   


You are mutating the list that you are iterating over so in essence you 
are looking at the word in list index 0, testing it, and removing it, 
then moving onto list index 1 but now your list has 'amazing' in index 0 
so that does not get checked.


The simplest way is to iterate through a new list with this
for word in candidates[:]:

That will create a new list that you will iterate over while you mutate 
the original list.


--
Kind Regards,
Christian Witts


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] trouble with list.remove() loop

2010-09-28 Thread Steven D'Aprano
On Tue, 28 Sep 2010 06:55:15 pm Christian Witts wrote:

 You are mutating the list that you are iterating over so in essence
 you are looking at the word in list index 0, testing it, and removing
 it, then moving onto list index 1 but now your list has 'amazing' in
 index 0 so that does not get checked.

 The simplest way is to iterate through a new list with this
  for word in candidates[:]:

 That will create a new list that you will iterate over while you
 mutate the original list.



Another technique is to iterate over the list backwards, so you are only 
ever deleting words you've already seen:

for i in range(len(candidates)-1, -1, -1)):
word = candidates[i]
if some_test():
del candidates[i]


I know the series of -1, -1, -1 is ugly, but that's what it takes.


-- 
Steven D'Aprano
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] trouble with list.remove() loop

2010-09-28 Thread Peter Otten
D Ryan (2) wrote:

 Hello all,
 I am currently trying to write a program which can find the solution to a
 game of hangman.
 In a part of the program, a user inputs a letter, a tester tells him if
 the word contains that letter, and then if the answer is no, all words
 containing that letter are removed from the list of remaining candidates.
 However, the code I've written seems to remove some, but not all the words
 containing the letter. Strangely though, if i run it a few more times it
 gets some of the ones it missed the 1st time round, untill after enough
 iterations it gets all of them. I cant understand why it doesnt remove all
 of them the first time round. I have cut the offending code and formatted
 it to work on its own, and also to fit into a relatively short email.
 
 # A sample list of words, one of which is the answer.
 candidates = [abacus,amazing,
   ozimandias,
   a,alphanumeric,
   functioning]
 
 # In the following code, the user has guessed the letter 'a',
 # and the tester has told him that the letter 'a' is not in the word.
 
 user_guess=a
 tester_response=no
 
 # The following code should eliminate all words which contain the letter
 # 'a', leaving only the word 'functioning' in the list
 
 if tester_response in (No,no,n,N,NO):
 for word in candidates:
 if user_guess in word:
 print word, removed..
 candidates.remove(word)
 print candidates
 
 Running once gives this output
 
 abacus removed..
 ozimandias removed..
 alphanumeric removed..
 ['amazing', 'a', 'functioning']
 
 But if i run it again it successfully removes 'amazing, and the next time
 it removes 'a', leaving the correct answer. I'm perplexed by this strange
 behaviour and would be most appreciative of any help. I'm very new to
 python so apologies for any formatting/style errors, and also for the
 simplicity of the problem.

I'd like to point out a robust method to avoid such pitfalls: create a new 
list instead of modifying the old one:

old_candidates = candidates
candidates = []
for word in old_candidates:
if user_guess in word:
print word, removed
else:
candidates.append(word)
print candidates

Often you can simplify that to a list comprehension like

candidates = [word for word in candidates if user_guess not in word]

Peter

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor