0

I have a list of the same type object. And i want to iterate that list and remove the object in it which reach a special condition. as follow:

    links = [{"source":0, "target":1}, ....]
    for link in links:
        if {"source":link["target"], "target":link["sourcec"]} not in links:
            links.remove(link)

but i find the for loop didn't access each element in list. so i guess the for loop based the index of the list. is there a good way to do that remove operation?

stamaimer
  • 6,227
  • 5
  • 34
  • 55
  • an example would be better. – Avinash Raj Mar 31 '15 at 02:30
  • If you are looking to remove any links that don't have a return link then while it is not advisable to update a list you are iterating over this should work... can you share expected output and any error. – AChampion Mar 31 '15 at 02:35
  • Please provide a short, complete program that demonstrates the problem you are having. – Robᵩ Mar 31 '15 at 02:44
  • i find that when loop through the list, it will skip some elements after execute the remove operation. so i want to if the for each loop in python is index based – stamaimer Mar 31 '15 at 02:47

5 Answers5

5

The built-in function filter does what you want. Here is one way to use it:

links = [{"source":0, "target":1},
         {"source":0, "target":2},
         {"source":0, "target":3},
         {"source":1, "target":0}]

links = filter(
    lambda link: {"source":link["target"], "target":link["source"]} in links,
    links)

print links

As an alternative, you could use a list comprehension:

links = [link
         for link in links
         if {"source":link["target"], "target":link["source"]} in links
        ]

Or, as others have pointed out, you can make a copy of your original list, and iterate that copy:

for link in links[:]:
    if {"source":link["target"], "target":link["source"]} not in links:
        links.remove(link)
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
0

You can create a new list which is a subset of the original list, then throw away the original list.

Kozyarchuk
  • 21,049
  • 14
  • 40
  • 46
  • This is the preferred Python approach - instead of deleting unwanted list entries, create a new list of just the entries you want, and then reassign that to the original list's variable name. – PaulMcG Mar 31 '15 at 02:47
0

The reason is that you modify your list during your iteration.

You can make it copied if your list is not that big:

import copy

links = [{"source":0, "target":1}, ]
links_copy = copy.copy(links)
for link in links:
    if {"source":link["target"], "target":link["source"]} not in links:
        links_copy.remove(link)

links = links_copy
flycee
  • 11,948
  • 3
  • 19
  • 14
  • what if the list large? i think the for each loop no matter how i modify the original list it still access each elelmet left in the list. – stamaimer Mar 31 '15 at 02:51
0

It looks like you are modifying the list that you are iterating over. That might cause some indices to get skipped because of how the indices shift when you remove elements. I think that this can be solved by making use of list comprehensions that look like this:

list = [x for x in list if <condition>]

For more information: http://www.secnetix.de/olli/Python/list_comprehensions.hawk

Edit: Rob seems to have posted an answer with list comprehensions while I was writing mine. Please refer to his as he presented additional methods

cyneo
  • 876
  • 7
  • 9
-2
links = [{1:2, 2:4}]
for link in links:
    if {1:3, 5:6} not in links:
        links.remove(link)
links

>>> []

Works fine. You must be doing something you are not expecting. Your logic seems pretty likely to empty your list under most conditions. Do you want the 3rd line to be "... not in link:", instead of "links"?

Fred Mitchell
  • 2,145
  • 2
  • 21
  • 29
  • Only works if there is only 1 element in the list. – PaulMcG Mar 31 '15 at 02:46
  • If the `if` statement, is true, the list won't change at all. – Zizouz212 Mar 31 '15 at 02:49
  • The if statement is true, so the first link, only link in this case, was deleted. There are no other links for the comparison, but each not matching one, will in turn be deleted, leaving links shorter than it was originally unless each link in the list is {1:3, 5:6}. – Fred Mitchell Mar 31 '15 at 02:54