-3

I'm looking for a way to loop twice on the same list at the same time as removing some items from this list. I noticed with the code below that looping twice on the same list at the same time as removing elements from this list leads to elements that are not processed.

a=[1,3,1,9]

for i in a:
    print(i ,"element from the frist loop for")
    for j in a:
        if i==j:
            p=a.index(i)
            del a[p]
            print(a ,"list after removing element in the second loop for")

Result:

1 element from the frist loop for
[3, 1, 9] list after removing element in the second loop for
[3, 9] list after removing element in the second loop for
9 element from the frist loop for
[3] list after removing element in the second loop for

The number 3 is not processed because it is not iterated from the first loop

In the first loop we went from 1 to 9 and jumped 3. I want to process also 3 in the first loop.

I understood that the way to loop the list with for loop is frozen by default before running the loop for. In the example the list a must be traversed of the index 0 to 3 since there are 4 numbers in the list so the value 3 has index 1. Knowing that in the first iteration we removed the 1 of the list a, the value 3 no longer has index 1 but 0. But as the index 0 has already been scanned so the value 3 is skipped.

Here true code:

a=[object1,object3,object1,object9]

for i in a:
    print(i ,"element from the frist loop for")
    for j in a:
        if distance(i,j) == 0:
            p=a.index(i)
            del a[p]
            print(a ,"list after removing element in the second loop for")

I try to delete two elements if they are close ( euclidean distance) otherwise I keep them in the list. All these elements are in the same list, hence the double looping on the same list

  • 3
    The immutables, Deep Copy to the rescue. – DirtyBit Feb 19 '19 at 08:11
  • 1
    Changing the length of an iterable whilst iterating over it can result in significant issues. I suggest you avoid it if you possibly can. Likely the most straightforward approach is to duplicate your original list to use as a reference, and delete from the one you're not iterating over. – Andrew Feb 19 '19 at 08:13
  • Post a desired output as well. – DirtyBit Feb 19 '19 at 08:18
  • if you want to get a new list without duplicates ( as per i get from your code) , you can use set operation. `a= list(set(a))` – sahasrara62 Feb 19 '19 at 08:19
  • In the original code I try to delete two elements if they are close otherwise I keep them in the list. All these elements are in the same list, hence the double looping on the same list. – pedro colombino Feb 19 '19 at 08:19
  • @pedrocolombino What do you mean by *close*? What should be desired output? – DirtyBit Feb 19 '19 at 08:20
  • Iterating backward the old-fashioned way using the index and while loop won’t skip items. Still it’s not recommended. – Tim Feb 19 '19 at 08:36

2 Answers2

2

The simplest way to remove duplicates from a list is with the builtin set() function. In your case:

list(set(a))

If you want to use a loop, though, you can just create a new list instead of trying to modify the one you're iterating over. There are a variety of (much) more efficient ways to do this, but here's a simple example of what I mean:

a=[1,3,1,9]
b = []

for i in a:
    if i in b:
        continue
    else:
        b.append(i)

For a more efficient method that avoids scanning the entire list for each item, you can use this recipe from itertools documentation:

from itertools import filterfalse

def unique_everseen(iterable, key=None):
    seen = set()
    seen_add = seen.add
    if key is None:
        for element in filterfalse(seen.__contains__, iterable):
            seen_add(element)
            yield element
    else:
        for element in iterable:
            k = key(element)
            if k not in seen:
                seen_add(k)
                yield element
DirtyBit
  • 16,613
  • 4
  • 34
  • 55
J. Taylor
  • 4,567
  • 3
  • 35
  • 55
  • I'm not looking for to delete duplicates in the list. I want to delete elements (vectors) that are near, for example in using a euclidean distance. – pedro colombino Feb 19 '19 at 08:30
  • 1
    Well then why didn't you say that in your question? You shared code which was trying to remove duplicates from a list and said nothing about what you were actually trying to do ... so what would you expect? – J. Taylor Feb 19 '19 at 08:32
  • I modified my post ^^ – pedro colombino Feb 19 '19 at 08:40
2

First, you should avoid to modifiy an iterable while you're interating on it. That could be very tricky.

I think the item 3 is not processed because when you use the a.index() method, the current index of a is moved to the position of the second 1, skipping the 3.

You could avoid this kind of issue by creating a new list

a=[1,3,1,9]
a2 = list(a) # Or use `deepcopy` if your list contains other mutables like dict or lists

for p, i in enumerate(a):
    print(i ,"element from the frist loop for")
    for j in a:
        if i==j:
            del a2[p]
            print(a ,"list after removing element in the second loop for")

Update

Eventually, you could simplify this problem by using lists comprehension, for example:

a2 = [i for p, i in enumerate(a) if i > 0]
olinox14
  • 6,177
  • 2
  • 22
  • 39