Python: For-in Loop Is Not Checking The Last String In A List, Why?
I'm using a for-in loop to remove any strings from a list titled "words" that start with "x" as part of a function, but find that this loop will not check the last string in the list. Why is this?
After adding some print statements to figure out where things were going wrong I narrowed it down to the second for-in loop, but beyond that I'm not sure what to do...
def front_x(words): print '\n' words.sort() print words words2 =  for string in words: if string == 'x': words2.append(string) #print 'added ' + string + ' to words2' #else: #print '(append)checked ' + string for string in words: if string == 'x': words.remove(string) print 'removed ' + string else: print 'checked ' + string words2.extend(words) return words2
As you can see, in each case it will check all of the elements in the list printed above except for the last. Below that are what my program got vs what it is supposed to get.
['axx', 'bbb', 'ccc', 'xaa', 'xzz'] checked axx checked bbb checked ccc removed xaa X got: ['xaa', 'xzz', 'axx', 'bbb', 'ccc', 'xzz'] expected: ['xaa', 'xzz', 'axx', 'bbb', 'ccc'] ['aaa', 'bbb', 'ccc', 'xaa', 'xcc'] checked aaa checked bbb checked ccc removed xaa X got: ['xaa', 'xcc', 'aaa', 'bbb', 'ccc', 'xcc'] expected: ['xaa', 'xcc', 'aaa', 'bbb', 'ccc'] ['aardvark', 'apple', 'mix', 'xanadu', 'xyz'] checked aardvark checked apple checked mix removed xanadu X got: ['xanadu', 'xyz', 'aardvark', 'apple', 'mix', 'xyz'] expected: ['xanadu', 'xyz', 'aardvark', 'apple', 'mix']
You are mutating the list as you are iterating over it. Behind the scenes Python is stepping through the numeric index of each item in the list. When you remove an item, all of the items with a higher index are shifted.
Instead, build an list of the indices you want to remove, then remove them. Or use a list comprehension to build a new list.
def front_x(words): words2 = [w for w in words if w.startswith('x')] return words2
If you want to also mutate the original list (modify
words) with the function you can do so using:
def drop_front_x(words): words2 =  indices = [i for i, w in enumerate(words) if w.startswith('x')] for ix in reversed(indices): words2.insert(0, words.pop(ix)) return words2
- → What are the pluses/minuses of different ways to configure GPIOs on the Beaglebone Black?
- → Django, code inside <script> tag doesn't work in a template
- → React - Django webpack config with dynamic 'output'
- → GAE Python app - Does URL matter for SEO?
- → Put a Rendered Django Template in Json along with some other items
- → session disappears when request is sent from fetch
- → Python Shopify API output formatted datetime string in django template
- → Shopify app: adding a new shipping address via webhook
- → Shopify + Python library: how to create new shipping address
- → shopify python api: how do add new assets to published theme?
- → Access 'HTTP_X_SHOPIFY_SHOP_API_CALL_LIMIT' with Python Shopify Module