On Jun 8, 8:17 am, [EMAIL PROTECTED] wrote: > On Jun 7, 5:56 pm, John Machin <[EMAIL PROTECTED]> wrote: > > > > > On Jun 8, 6:05 am, [EMAIL PROTECTED] wrote: > > > > On Jun 7, 2:42 pm, "Daniel Fetchinson" <[EMAIL PROTECTED]> > > > wrote: > > > > > > Hi. I'd like to port a Perl function that does something I don't > > > > > know how to do in Python. (In fact, it may even be something that > > > > > is distinctly un-Pythonic!) > > > > > > The original Perl function takes a reference to an array, removes > > > > > from this array all the elements that satisfy a particular criterion, > > > > > and returns the list consisting of the removed elements. Hence > > > > > this function returns a value *and* has a major side effect, namely > > > > > the target array of the original argument will be modified (this > > > > > is the part I suspect may be un-Pythonic). > > > > > > Can a Python function achieve the same effect? If not, how would > > > > > one code a similar functionality in Python? Basically the problem > > > > > is to split one list into two according to some criterion. > > > > > This function will take a list of integers and modify it in place such > > > > that it removes even integers. The removed integers are returned as a > > > > new list (disclaimer: I'm 100% sure it can be done better, more > > > > optimized, etc, etc): > > > > > def mod( alist ): > > > > old = alist[:] > > > > ret = [ ] > > > > for i in old: > > > > if i % 2 == 0: > > > > ret.append( alist.pop( alist.index( i ) ) ) > > > > > return ret > > > > > x = range(10,20) > > > > > print x > > > > r = mod( x ) > > > > print r > > > > print x > > > > > HTH, > > > > Daniel > > > > -- > > > > Psss, psss, put it down! -http://www.cafepress.com/putitdown > > > > def mod( alist ): > > > return [ alist.pop( alist.index( x ) ) for x in alist if x % 2 == > > > 0 ] > > > > alist = range(10,20) > > > blist = mod( alist ) > > > > print alist > > > print blist > > > > The same thing with list comprehensions. > > > Not the same. The original responder was careful not to iterate over > > the list which he was mutating. > > > >>> def mod(alist): > > > ... return [alist.pop(alist.index(x)) for x in alist if x % 2 == 0] > > ...>>> a = range(10) > > >>> print mod(a), a > > > [0, 2, 4, 6, 8] [1, 3, 5, 7, 9]>>> a = [2,2,2,2,2,2,2,2] > > >>> print mod(a), a > > > [2, 2, 2, 2] [2, 2, 2, 2] > > # should be [2, 2, 2, 2, 2, 2, 2, 2] [] > > Alas, it appears my understanding of list comprehensions is > significantly less comprehensive than I thought =)
It's nothing to do with list comprehensions, which are syntactical sugar for traditional loops. You could rewrite your list comprehension in the traditional manner: def mod(alist): ret = [] for x in alist: if x % 2 == 0: ret.append(alist.pop(alist.index(x)) return ret and it would still fail for the same reason: mutating the list over which you are iterating. At the expense of even more time and memory you can do an easy fix: change 'for x in alist' to 'for x in alist[:]' so that you are iterating over a copy. Alternatively, go back to basics: >>> def modr(alist): ... ret = [] ... for i in xrange(len(alist) - 1, -1, -1): ... if alist[i] % 2 == 0: ... ret.append(alist[i]) ... del alist[i] ... return ret ... >>> a = [2,2,2,2,2,2,2,2,2] >>> print modr(a), a [2, 2, 2, 2, 2, 2, 2, 2, 2] [] >>> HTH, John -- http://mail.python.org/mailman/listinfo/python-list