>>> a = [1, 2, 3, 4, 5]
>>> for x in a:
... if x == 3:
... a.remove(x)
... print x
...
1
2
3
5
>>> a
[1, 2, 4, 5]
>>>
Sure, the resulting list is correct. But 4 is never printed during the
loop!
What I was really trying to do was this:
apps = [name for name in os.listdir(ROOT) if
os.path.isdir(os.path.join(ROOT, name))]
apptitles = {}
for name in apps:
try:
app = __import__(name)
except:
apps.remove(name)
else:
apptitles[name] = getattr(app, 'TITLE', name.title())
which worked fine, until I actually had a directory with no module in it.
Then that directory was correctly removed from the list, but the _next_
one was skipped, so its title was never assigned, which caused problems
later in the program.
--
09 F9 11 02 9D 74 E3 5B D8 41 56 C5 63 56 88 C0 -- pass it on
You have to iterate over a copy of 'a', so for x in a[:]. Modifying a
list while iterating over is a recipe for problems. (As it is in many
other programming languages.)
Berteun
You should not change/modify the original sequence iterating over.
In the list comprehension, try changing os.listdir(ROOT) to
os.listdir(ROOT)[:] so you are get a copy of the original list.
geoff.
If you're going to delete elements from
a list while iterating over it, then do
it in reverse order:
>>> a = [ 98, 99, 100 ]
>>> last_idx = len(a) - 1
>>> for i, x in enumerate(a[::-1]):
... if x == 99: del(a[last_idx - i])
... print x
...
100
99
98
>>> a
[98, 100]
--
Hope this helps,
Steven
Why so hard? Reversing it that way creates a copy, so you might as
well do:
>>> a = [ 98, 99, 100 ]
>>> for i, x in enumerate(a[:]):
... if x == 99: del(a[i])
... print x
Berteun
Well ... you could use:
>>> for i in range(len(a)-1, -1, -1):
... print a[i]
... if a[i] == 3: del a[i]
...
5
4
3
2
1
>>> print a
[1, 2, 4, 5]
Bye.
Why so hard?
>>> a = [ 98, 99, 100, 98, 99, 100 ]
>>> for i, x in enumerate(a[:]):
if x == 99: del(a[i])
>>> a
[98, 100, 98, 99]
oops! But:
>>> a = [ 98, 99, 100, 98, 99, 100 ]
>>> last_idx = len(a) - 1
>>> for i, x in enumerate(a[::-1]):
if x == 99: del(a[last_idx - i])
>>> a
[98, 100, 98, 100]
Reversing it works. Your code doesn't.
How about...
for name in apps:
try:
app == __import__(name)
apptitles[name] = getattr(app, 'TITLE', name.title())
except ImportError:
pass
# Remove apps with no title, ie those that didn't import.
apps = [name for name in apps if apptitles.get(name)]
Alternatives for the last line would be 'apps = filter(apptitles.get,
apps)'
or 'apps = apptitles.keys()'.
--
Paul Hankin
Why so hard? :)
a = [x for x in a if x != 99]
OK, so this doesn't modify a in place.. but how often do you really
need to do that?
If I really had to modify it in place (and the condition wasn't really
x == 99), how about:
bad_indices = [i for i, x in enumerate(a) if x == 99]
for bad_index in reversed(bad_indices):
del a[bad_index]
--
Paul Hankin
how about
>>> li = [1,2,3,4,5]
>>> filter(lambda x: x != 3, li)
[1, 2, 4, 5]
>>>
I haven't measured it, but this should be the fast solution in all
the thread ...
li.remove(3) is probably faster.
But that only removes the first ocurrence of item==3.
In a = [1, 2, 3, 3, 3, 4, 3, 3, 2, 3], the filter solution will
efectively remove all items with value == 3 while li.remove(3) will
only remove the first ocurrence.
Bye!
from itertools import ifilter
print [x for x in ifilter(lambda x: x != 99, li)]
Will this one be faster or slower than filter?
Hmm, interesting, I didn't realize that (shoulda checked the docs).
Thanks!
Or one could use the trick of counting from the right (untested):
n = len(a)
for i, x in enumerate(a):
if x == 99: del a[i-n]
--
Arnaud
Or one can put on his bellbottoms, horn-rimmed glasses, and wear a mullet:
i = 0
while i < len(a):
if a[i] == 99:
del a[i]
else:
i += 1
--
Neil Cerutti <mr.cerut...@gmail.com>
def inplacefilter(pred, alist):
"""inplacefilter(pred, alist): filters the given list like
filter(),
but works inplace, minimizing the used memory. It returns None.
>>> pr = lambda x: x > 2
>>> l = []
>>> inplacefilter(pr, l)
>>> l
[]
>>> l = [1,2,2]
>>> inplacefilter(pr, l)
>>> l
[]
>>> l = [3]
>>> inplacefilter(pr, l)
>>> l
[3]
>>> l = [1,2,3,1,5,1,6,0]
>>> r = filter(pr, l) # normal filter
>>> r
[3, 5, 6]
>>> inplacefilter(pr, l)
>>> r == l
True
"""
slow = 0
for fast, item in enumerate(alist):
if pred(item):
if slow != fast:
alist[slow] = alist[fast]
slow += 1
del alist[slow:]
If you use Psyco you can replace the enumerate() with a manually
incremented counter to speed up the code a bit, like this (untested):
def inplacefilter(pred, alist):
slow = 0
fast = 0
for item in alist:
if pred(item):
if slow != fast:
alist[slow] = alist[fast]
slow += 1
fast += 1
del alist[slow:]
Bye,
bearophile
Quadratic time!! Yowch!! Back to the future:
def rocket_science(xs):
for x in xs:
if x != 99:
yield x
a[:] = list(rocket_science(a))
;-)
> n = len(a)
> for i, x in enumerate(a):
> if x == 99: del a[i-n]
Oops. That can't work. Don't know what I was thinking here. I
probably did had one mental refactoring too many...
--
Arnaud
Heh.
<lamely>It's probably a fairly peppy quadratic operation though.</lamely>
Besides, wherever will I find plutonium or a bolt of lightning?
--
Neil Cerutti <mr.cerut...@gmail.com>
> Quadratic time!! Yowch!! Back to the future:
>
> def rocket_science(xs):
> for x in xs:
> if x != 99:
> yield x
>
> a[:] = list(rocket_science(a))
I call "useless use of list"!
a[:] = rocket_science(a)
:-)
> Anyone else noticed that the OP has not actually replied to any of the
> suggestions...
Sorry. I was just fascinated at the turns it was taking. But the first
answer was fine for me:
for name in apps[:]:
etc.
Thanks all.