problem Deleting list items in a for loop (python)

20,283

Solution 1

The below code will fix your issue. You have to iterate over a copy of the list. You can't remove items from the list you are iterating over.

import copy

def main():
    titles_list = ["English", "Math", "History", "IT", "Biology", "Spanish"]
    titles_list_orig = copy.deepcopy(titles_list)

    for title in titles_list_orig:
        print "Do you want to keep the title:", title , "\n or Delete it? Input Y for keep, N for Delete "
        Question = raw_input()
        if str(Question.upper()) == "N":
            titles_list.remove(title)

    print titles_list

Solution 2

Your code actually has two major issues.

The first is that you are not calling the upper method, but merely referencing it. You need to actually call it (via Question.upper()) as w00t does in his answer.

Putting some diagnostic print statements inside your loop would have been a good way to see that (especially printing out str(Question.upper)) (Tangent: Question is a bad name for a variable that holds the answer to a question the program asked of the user)

Secondly, removing already seen items from a list you're iterating over will result in skipping values. You don't actually need to copy the whole list to deal with that - just iterating over it in reverse is enough to fix the problem.

Finally, a couple of minor cosmetic points are that raw_input() accepts a prompt argument, so you don't need a separate print statement and calling upper() on a string will itself always return a string:

titles_list = ["English", "Math", "History", "IT", "Biology", "Spanish"]
prompt = ("Do you want to keep the title: {}\n"
          "or Delete it? Input Y for keep, N for Delete: ")

for title in reversed(titles_list):
    answer = raw_input(prompt.format(title))
    if answer.upper() == "N":
        titles_list.remove(title)

print titles_list

Solution 3

I think the main issue in your code was incorrect usage of upper function. Once you fix it, you can remove the titles from the list as you please. You can either use index or the value. Here is the code snipped that worked for me

#!/usr/bin/python

import string

titles_list = ["English", "Math", "Biology", "IT", "History"]
for title in titles_list:
  answer = raw_input("Do you want to keep this title %s, type y or n\n" % (title))
  if string.upper(answer) == "N":
    # i = titles_list.index(title)
    # del titles_list[i]
    titles_list.remove(title)
    print "now list is" , titles_list
print titles_list

Please see the commented lines using index. Also, you can make your code more concise using the raw_input(prompt) feature.

You also need to think about the scenario where there are multiple occurrences of the same titles in your list, in that case I suggest get all the indices for the title till the list is empty and delete the titles using del(index) as the solutions presented above will remove only the first occurrence of the title.

Solution 4

I know there is an answer already, here is another way for completeness, and to demonstrate list comprehension.

This method takes a list, asks to keep each item, and returns a new list excluding the ones marked for deletion:

def delete_items(titles):
    deleted_items = []
    for title in titles:
        print('keep %s?' % title)
        if str(raw_input().upper()) == 'N':
            deleted_items.append(title)
    return [e for e in titles if e not in deleted_items]
Share:
20,283

Related videos on Youtube

RY4N
Author by

RY4N

Updated on July 09, 2022

Comments

  • RY4N
    RY4N almost 2 years

    Possible Duplicate:
    Remove items from a list while iterating in Python

    Hi im having a problem i cant seem to delete items whilst iterating through a list in python, Here is what i've got: a title should be removed if a user Inputs n or N when asked the question to delete in the for loop, the problem is that when its all done the items are all still there and none have been removed...

        titles_list = ["English", "Math", "History", "IT", "Biology", "Spanish"]
    
        for title in titles_list:
            print "Do you want to keep the title:", title , "\n or Delete it ? Input Y for keep, N for Delete "
            Question = raw_input()
            if str(Question.upper) == "N":
                titles_list.remove(title)
    
    print titles_list
    
  • RY4N
    RY4N about 13 years
    thanks :D i used splice cause its less lines but u lead me to needing to copy it thanks
  • ncoghlan
    ncoghlan about 13 years
    No need to copy it, just iterate over it in reverse so the removals don't affect the items you see while iterating.
  • Sumod
    Sumod about 13 years
    @ncoghlan - can you please elaborate on your answer. not clear to me.
  • Wang Dingwei
    Wang Dingwei about 13 years
    You might want to mention that new style string formatting only works in python 2.7 and later.
  • Richard Stagg
    Richard Stagg about 13 years
    alternative to deepcopy, you can also use orig = list(titles) to copy a list :-)
  • Steve Jessop
    Steve Jessop about 13 years
    @Wesley: agreed, in fact that's more appropriate in general (i.e. for things other than strings), since it's a shallow copy rather than a deep copy. We don't need copies of the contents of titles_list.
  • ncoghlan
    ncoghlan about 13 years
    It's actually available in 2.6 or later
  • ncoghlan
    ncoghlan about 13 years
    @Sumod I elaborated on it a little more in my own answer.
  • ncoghlan
    ncoghlan about 13 years
    But yeah, if you need to use 2.5 or earlier, then the {} in the format string needs to be replaced with a %s and the formatting command itself becomes prompt % title.
  • ncoghlan
    ncoghlan about 13 years
    No need to use the string module - answer.upper() works just fine. However, did you actually try this and see what happens when you press n every time? You won't be offered a chance to remove "Math" or "IT" from the list.
  • Morg.
    Morg. almost 11 years
    ncoghlan. nice way to run around the python design
  • domokun
    domokun about 10 years
    Why would you manually copy the list when you can already cycle over a copy with for title in titles_list[:] ?

Related