1

I would like to compare the elements of a list, and at the end of each for loop the combination resumes with the new updated list.

from itertools import combinations

aListe = ['a', 'b', 'c', 'd']
for first, second in combinations(aListe, 2):
    # do something
    aListe.remove(first)
ValueError: list.remove(x): x not in list

more specific example of the # do something.

Imagine my list contains shapely polygon such as

aListe = [polygon1, polygon2, polygon3, polygon4]
for first, second in combinations(aListe, 2):
    if area(first) > area(second):
        aListe.remove(first)

if the area of the first polygon in the list is already greater than the second I don't want it to be compared to the others. I would like the next for loop start on an updated list without the first polygon.

Tim
  • 513
  • 5
  • 20
  • If you want to *compare* elements of a list, why do you *remove* something from the list? – mkrieger1 Jul 02 '21 at 14:37
  • Can you show what you expect to be the value of the list in each iteration? – mkrieger1 Jul 02 '21 at 14:38
  • Because depending on the result of each loop (in my #do something) I don't want to compare all the values between them. – Tim Jul 02 '21 at 14:40
  • @mkrieger1 I edited with an example. – Tim Jul 02 '21 at 14:51
  • In other words, you want to find the polygon in the list with the smallest area? – mkrieger1 Jul 02 '21 at 14:56
  • 1
    i feel like a cobination of vectorizing and builtins would work better for you – Eumel Jul 02 '21 at 14:57
  • @mkrieger1 No, this is just an example. In my case I want to do a comparison on polygons with several #do something which can be complex, and at the end a polygon is deleted etc.. Thus it would be nice for me to just know is it possible to simply update a list during an itertools.combinations() at each iteration ? – Tim Jul 02 '21 at 15:01
  • @Eumel Can you give me a small example? – Tim Jul 02 '21 at 15:02
  • make a list of areas and then use np.min(areas) (or np.argmin if you need the index) – Eumel Jul 02 '21 at 15:05

1 Answers1

3

As you have seen, your code failed because itertools.combinations visits each list item multiple times and it can only be removed once (assuming that it is only contained once).

But even if you had added a check like if first in aList to circumvent this error, you might have gotten unexpected results, as is generally the case when removing items from a list while iterating over it, see Removing from a list while iterating over it.

In your case, instead of actually removing a polygon from the list, I would mark it as "removed" by adding it to a "removed" set, and skip an iteration if an already removed polygon is encountered again.

(Note, in order to add polygons to a set, if I understand https://shapely.readthedocs.io/en/stable/manual.html correctly, "[…] use the geometry ids as keys since the shapely geometries themselves are not hashable.")

from itertools import combinations

removed = set()
aListe = [polygon1, polygon2, polygon3, polygon4]
for first, second in combinations(aListe, 2):
    if id(first) in removed:
        continue
    if area(first) > area(second):
        removed.add(id(first))
VirtualScooter
  • 1,792
  • 3
  • 18
  • 28
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • 2
    +1, but a point to note: I totally agree that you shouldn't, but you *can* change the original list while iterating over the combinations as long as you make sure you don't try to remove the same element twice (which causes the `ValueError` the OP faced). – fsimonjetz Jul 02 '21 at 15:16