Strange behavior

Steven D'Aprano steve+comp.lang.python at pearwood.info
Tue Aug 14 20:19:55 EDT 2012


On Tue, 14 Aug 2012 21:40:10 +0200, Virgil Stokes wrote:

> You might find the following useful:
> 
> def testFunc(startingList):
>      xOnlyList = []; j = -1
>      for xl in startingList:
>          if (xl[0] == 'x'):

That's going to fail in the starting list contains an empty string. Use 
xl.startswith('x') instead.


>              xOnlyList.append(xl)
>          else:
>              j += 1
>              startingList[j] = xl

Very cunning, but I have to say that your algorithm fails the "is this 
obviously correct without needing to study it?" test. Sometimes that is 
unavoidable, but for something like this, there are simpler ways to solve 
the same problem.


>      if j == -1:
>          startingList = []
>      else:
>          del startingList[j:-1]
>      return(xOnlyList)


> And here is another version using list comprehension that I prefer

> def testFunc2(startingList):
>      return([x for x in startingList if x[0] == 'x'], [x for x in
> startingList if x[0] != 'x'])

This walks over the starting list twice, doing essentially the same thing 
both times. It also fails to meet the stated requirement that 
startingList is modified in place, by returning a new list instead. 
Here's an example of what I mean:

py> mylist = mylist2 = ['a', 'x', 'b', 'xx', 'cx']  # two names for one 
list
py> result, mylist = testFunc2(mylist)
py> mylist
['a', 'b', 'cx']
py> mylist2  # should be same as mylist
['a', 'x', 'b', 'xx', 'cx']

Here is the obvious algorithm for extracting and removing words starting 
with 'x'. It walks the starting list only once, and modifies it in place. 
The only trick needed is list slice assignment at the end.

def extract_x_words(words):
    words_with_x = []
    words_without_x = []
    for word in words:
        if word.startswith('x'):
            words_with_x.append(word)
        else:
            words_without_x.append(word)
    words[:] = words_without_x  # slice assignment
    return words_with_x


The only downside of this is that if the list of words is so enormous 
that you can fit it in memory *once* but not *twice*, this may fail. But 
the same applies to the list comprehension solution.



-- 
Steven



More information about the Python-list mailing list