4

while i'm interating a list, how can i get the id of the current item to reference it to list methods?

xl = [1,2,3] # initial list
yl = [3,2]   # list used to remove items from initial list

for x in xl[:]:
    for y in yl:
        if x == y:
            xl.pop(x) # problem
            break
        print x, y
print xl

in the simple example, i want to loop through the 2 lists, and when i find a similar item, remove it from list 1.

What should i use instead of X in the line commented with "#problem"?

PS: Note it's a copy i'm iterating from.

3 Answers 3

8

The general way to do this is with enumerate.

for idx, item in enumerate(iterable):
  pass

But for your use case, this is not very pythonic way to do what you seem to be trying. Iterating over a list and modifying it at the same time should be avoided. Just use a list comprehension:

xl = [item for item in xl if item not in yl]
1
  • 1
    +1 for enumerate but to clarify, its ok to modify a list while looping in terms of changing the value of indexes but not the size of the list. Though doing it over a copy is safe though maybe not efficient.
    – jdi
    Commented Feb 6, 2012 at 1:12
4

How about xl = [x for x in xl if x not in y]

This is known as a list comprehension.

5
  • it was a 'simple example'. it will require http requests and what not to make the check, not just matching two numbers.
    – gcb
    Commented Feb 6, 2012 at 0:57
  • 2
    @gcb That's not a problem. You can check as much as you want, with xl = [x for x in xl if checkHttpRequestsAndWhatNot(x)], or shorter x1 = filter(x1, checkHttpRequestsAndWhatNot).
    – phihag
    Commented Feb 6, 2012 at 0:59
  • that's a good point... think i will review the structures i'm using right now.
    – gcb
    Commented Feb 6, 2012 at 1:05
  • It sounds as if you didn't really ask the question that you wanted answered. You might update the question to make it more precise. When you ask a simple question, you'll often find there is a simple answer available.
    – gfortune
    Commented Feb 6, 2012 at 1:51
  • the answer about enumerate answered the question just right, but you and phihag raised a good point about using list comprehension and a bunch of functions instead of a flag and a bunch of loops. but it's sideways to the question, i think
    – gcb
    Commented Feb 6, 2012 at 2:28
2

Instead of removing elements you don't like, you should simply use filter:

x1 = filter(x1, lambda x: x not in y1)

Alternatively, a list comprehension works as well:

x1 = [x for x in x1 if x not in y1]

If y1 is very large, you should look up in a set, like this:

y1set = set(y1)
x1 = filter(x1, lambda x: x not in y1set)

For reference, pop takes an index, and the generic way to get an index is enumerate. However, in nearly all cases, there's a shorter and cleaner way to write the code than using indices.

7
  • this is really a mapping to a database. so in this case i want to keep the indexes. in my business logic, when i remove from the DB, i will remove from the in memory list. think i will end up using explicity indexes matching the DB...
    – gcb
    Commented Feb 6, 2012 at 0:58
  • @gcb If you want to keep the indices, you shouldn't be using pop, but setting the entries in the x1 list to some marker value such as None.
    – phihag
    Commented Feb 6, 2012 at 1:00
  • i want to drop the indexes too.
    – gcb
    Commented Feb 6, 2012 at 1:04
  • @gcb Well, then simply use filter. Sorry, but I don't understand why you desperately want to call pop. pop is extremely slow by design, since it needs to copy a large part of the list and potentially reallocate the list afterwards.
    – phihag
    Commented Feb 6, 2012 at 1:06
  • i'm using it as sort of queue, so it may be slower, but it's the best analogy to not make the code too esoteric when i read it later :) but i may review that to use list comprehension instead of a queue.
    – gcb
    Commented Feb 6, 2012 at 1:10

Not the answer you're looking for? Browse other questions tagged or ask your own question.