0

I wonder how can i iterate over a list2 and remove all ittems that contains one of the list1 ittems ?

list1 = [6, 7, 8, 9]
list2=['0009', '0001', '0008', '0003', '0004', '0005', '0006', '0007']

and result will be :

list2=[ '0001',  '0003', '0004', '0005']

i try somthing like :

list1 = [6, 7, 8, 9]
list2=['0009', '0001', '0008', '0003', '0004', '0005', '0006', '0007']


for ittem in list2:
    for digit in ittem:
        if digit in ittem:
            list2.remove(ittem)

print(list2)

for ittem in list2: for digit in ittem: if digit in ittem: list2

result :ValueError: list.remove(x): x not in list

ps : i dont want to creat a new list , i want to remove ittems .. Any ideas ?

DYZ
  • 55,249
  • 10
  • 64
  • 93
medow
  • 33
  • 3
  • 1
    You are almost always better off simply creating a new list. Even if you simply create an intermediate list to assign to the old-list in place, e.g. `my_list[:] = [x for x in my_list if x in some_other_list]`. Also, you should consider making `some_other_list` a `set` object, for performance reasons, especially if it is large. – juanpa.arrivillaga Jan 24 '18 at 22:28
  • Where do you use `list1`? – DYZ Jan 24 '18 at 22:35
  • thanks but i realy need to remove ittems That's what my teacher wants. If there is a way to remove, that will help me a lot – medow Jan 24 '18 at 22:36
  • That *does* do that. – juanpa.arrivillaga Jan 24 '18 at 22:37
  • There is a long discussion here about what "in place" means: https://stackoverflow.com/questions/8037455/how-to-modify-python-collections-by-filtering-in-place. However, we shouldn't get bogged down in detail unless it really matters. "That's what my teacher wants" doesn't necessarily help with this. – jpp Jan 24 '18 at 22:49
  • @jp_data_analysis I think there is a very unambiguous test for *in-place* in Python, `x = []; in_place(x); print(x)` will modify `x`. – juanpa.arrivillaga Jan 24 '18 at 22:54
  • Nothing should get deleted since none of the list2 items contain any list1 item. – Stefan Pochmann Jan 24 '18 at 23:05

6 Answers6

3

You should avoid removing from a list in the middle. It will give you polynomial time complexity, and is a little tricky to get correct anyway. Removing items from a list while iterating over it will commonly cause you to skip items, as your list changes in size. However, it is possible to do it safely by iterating backwards over the sequence:

>>> list1 = [6, 7, 8, 9]
>>> list2=['0009', '0001', '0008', '0003', '0004', '0005', '0006', '0007']

Then simply:

>>> for i in reversed(range(len(list2))):
...     item = list2[i]
...     if any(int(c) in list1 for c in item):
...         del list2[i]
...
>>> list2
['0001', '0003', '0004', '0005']

However, it is almost always faster and more efficient and straight-forward to create a new list as an intermediate and use it to change the original list in-place:

>>> list2[:] = [x for x in list2 if any(int(c) in list1 for c in x)]
>>> list2
['0009', '0008', '0006', '0007']

Finally, if you are going to be checking membership in a list, consider using a set object instead. Checking if an item is in a list is a linear operation, versus constant time with a set.

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
1

Try a list comprehension:

list1_set = set(list1)
list2[:] = [x for x in list2 if int(x) not in list1_set]
jpp
  • 159,742
  • 34
  • 281
  • 339
1

If all list2 items are unique, you can remove them in a reversed iteration:

for item in reversed(list2):
    for number in list1:
        if str(number) in item:
            list2.remove(item)
            break
print(list2)
#['0001', '0003', '0004', '0005']
DYZ
  • 55,249
  • 10
  • 64
  • 93
  • @juanpa.arrivillaga Correct. That's why I said _if all `list2` items are unique_. – DYZ Jan 24 '18 at 22:42
  • @juanpa.arrivillaga Your solution is more robust and general, but possibly less efficient. (Which is such a common case!) – DYZ Jan 24 '18 at 22:44
  • The best solution in python is almost always `x[:] = `. It will be linear time, I'm pretty sure, but I don't feel like digging through the source code (the slicing code being particularly daunting, the last time I tried). – juanpa.arrivillaga Jan 24 '18 at 22:47
  • @juanpa.arrivillaga This still creates a _copy_ of the list before storing it in the same object. If the list is huge, making a copy may be a problem. – DYZ Jan 24 '18 at 22:48
  • Definitely, although, if your list truly is that huge, you are going to hurt pretty bad from the quadratic time complexity of the more memory efficient version, unless maybe the number of items removed is expected to be relatively small. – juanpa.arrivillaga Jan 24 '18 at 22:49
  • 1
    @juanpa.arrivillaga Agree, but often "time that we have is space that we have not." – DYZ Jan 24 '18 at 22:50
1

You can use re.findall:

import re
list1 = [6, 7, 8, 9]
list2=['0009', '0001', '0008', '0003', '0004', '0005', '0006', '0007']
new_list2 = filter(lambda x:int(re.findall('\d+(?=$)', x)[0]) not in list1, list2)

Output:

['0001', '0003', '0004', '0005']
Ajax1234
  • 69,937
  • 8
  • 61
  • 102
0

You can always use set intersection:

list1 = [6, 7, 8, 9]
list2=['0009', '0001', '0008', '0003', '0004', '0005', '0006', '0007']

list1 = set(map(str, list1))
# {'6', '8', '9', '7'}

list2[:] = [x for x in list2 if not list1.intersection(x)]

print(list2)

Which Outputs:

['0001', '0003', '0004', '0005']
RoadRunner
  • 25,803
  • 6
  • 42
  • 75
0

You can try something like this

list1 = [6, 7, 8, 9]
list2=['0009', '0001', '0008', '0003', '0004', '0005', '0006', '0007']

for i in list2:
    if int(list(i)[-1:][0]) not in list1:
        print(i)

output:

0001
0003
0004
0005