views:

205

answers:

5

I'm attempting to do a simple bubble sort code to get familiar with list/string manip & method use, but for some reason, when I attempt to iterate through each value in the list to remove white space and values that are non ints, it skips some. I haven't even gotten to the bubble sorting part..

#test data:  45,5j, f,e,s , , , 45,q,

    if __name__ == "__main__":
getList = input("Enter numbers separated by commas:\n").strip()
listOfBubbles = getList.split(',')
print (listOfBubbles)
i = 0
for k in listOfBubbles:
    listOfBubbles[i] = k.strip()
    print ("i = {0} -- Checking '{1}'".format(i,listOfBubbles[i]))
    if listOfBubbles[i] == '' or listOfBubbles[i] == ' ':
        del listOfBubbles[i]
        i -= 1
    else:
        try:
            listOfBubbles[i] = int(listOfBubbles[i])
        except ValueError as ex:
            #print ("{0}\nCan only use real numbers, deleting '{1}'".format(ex, listOfBubbles[i]))
            print ("deleting '{0}', i -= 1".format(listOfBubbles[i]))
            del listOfBubbles[i]
            i -= 1
        else:
            print ("{0} is okay!".format(listOfBubbles[i]))
    i += 1

print(repr(listOfBubbles))

Output:

    Enter numbers separated by commas:
45,5j, f,e,s , , , 45,q,
['45', '5j', ' f', 'e', 's ', ' ', ' ', ' 45', 'q', '']
i = 0 -- Checking '45'
45 is okay!
i = 1 -- Checking '5j'
deleting '5j', i -= 1
i = 1 -- Checking 'e'
deleting 'e', i -= 1
i = 1 -- Checking ''
i = 1 -- Checking '45'
45 is okay!
i = 2 -- Checking 'q'
deleting 'q', i -= 1
[45, 45, ' ', ' 45', 'q', '']
A: 

Never alter the very list you're looping on -- inside the loop for k in listOfBubbles:, you're deleting some items of that very list, and that upsets the internal looping logic. There are many alternative approaches, but the simplest fix is to loop on a copy of the list you want to change: for k in list(listOfBubbles):. There may be more issues, but this is the first one.

Alex Martelli
A: 

Nevermind, fixed it. I change the loop from a for.. to a while..

if __name__ == "__main__":
    getList = input("Enter numbers separated by commas:\n").strip()
    listOfBubbles = getList.split(',')
    print (listOfBubbles)
    i = 0
    while i < len(listOfBubbles):
        listOfBubbles[i] = listOfBubbles[i].strip()
        print ("i = {0} -- Checking '{1}'".format(i,listOfBubbles[i]))
        if listOfBubbles[i] == '' or listOfBubbles[i] == ' ':
            del listOfBubbles[i]
            i -= 1
        else:
            try:
                listOfBubbles[i] = int(listOfBubbles[i])
            except ValueError as ex:
                #print ("{0}\nCan only use real numbers, deleting '{1}'".format(ex, listOfBubbles[i]))
                print ("deleting '{0}', i -= 1".format(listOfBubbles[i]))
                del listOfBubbles[i]
                i -= 1
            else:
                print ("{0} is okay!".format(listOfBubbles[i]))
        i += 1

    print(repr(listOfBubbles))
Justen
A: 

You cannot use an iterator to delete from a list because the length changes.

Instead you must use an index in the for loop (or a while loop).

Once you have removed an item you need to loop through the list again.

psuedo-code:

again:
for i = 0 to list.count - 1
{
  if condition then 
    delete list[i] 
    goto again;
}
+1  A: 

How about a more pythonic way?

#input
listOfBubbles = ['45', '5j', ' f', 'e', 's ', ' ', ' ', ' 45', 'q', '']
#Copy input, strip leading / trailing spaces. Remove empty items
stripped = [x.strip() for x in listOfBubbles if x.strip()]    

# list(filtered) is ['45', '5j', 'f', 'e', 's', '45', 'q']
out = []
for val in filtered:
  try:
    out.append(int(val))
  except:
    # don't do anything here, but need pass because python expects at least one line
    pass 
# out is [45, 45]

Finally, to jump to your correct answer

out.sort()

Update To clarify pass

>>> for i in range(0,5):
        pass
        print i

0
1
2
3
4
Tom Leys
Hmm, this won't compile for me. I get a syntax error at the line with the lambda function. Also, I don't understand the: x and x != ' ', What does the first argument do (before the 'and')? For the except, why did you use pass instead of continue? And another question, does the list 'stripped' get deleted from memory when its passed through filter to the list 'filtered?'
Justen
Hopefully all your issues have been resolved by modifying my answer. Note I removed () in lambda (x): ... Python 3.0 prefers lambda x: ... . In python, '' evaluates to False, which is why we filter on x and x != ' ' - literally does the same thing your code used to do. Every line using [x for x in c] creates a totally new list.
Tom Leys
Since you are using modern python, I could remove the filter using an if on the stripped line. That is like an inline filter, again looking for '' after x.strip()
Tom Leys
Thanks for your help but I have 2 more questions. (1) Is pass the exact same thing as continue, or is there some difference? and (2) Is it good practice to delete the copied list? For instance, when you were using filter(), after that line would it be good practice to have: del stripped ?
Justen
(1) No, pass tells python to do absolutely nothing. It is just there to provide indenting. If there was more code after the pass, but before the end of the loop, it would be executed. (2) Python has an automatic garbage collector. All the intermediate variables I am throwing around will get deleted as soon as the method containing my code exits. Although you have no containing method in your example, I would reccomend making a method that takes listOfBubbles as an argument. I would then call this method from the if __name__ == "__main__"
Tom Leys
A: 

If you're going to delete from a list while iterating through it, traverse the list in reverse order:

for( i = myList.length - 1; i >= 0; i-- ) {
   // do something
   if( some_condition ) {
      myList.deleteItem( i );
   }
}

This way you won't skip any list items as shortening the list doesn't affect any future iterations. Of course, the above snippet assumes that the deleteItem method is supported in the list/array class and does the appropriate things.

Adnan