-1

I have two lists, both have a n of items. For example, I have list l=[1,5,10,5,10] and list del1=[5,10].

I am trying to remove the items in del1 once from l. So the desired outcome is a new list called a = [1,5,10].

I tried to do nested loop but I just couldn't figure it out, see my code below:

l= [1,5,10,5,10]

s=l

a=[]

count=0
del1=[5,10]
for i in del1:
    for x in s:
        a.append(x)
        if a ==i:
            a.remove(i)
        else:
            pass


print (a)

Any thoughts on this?

Pika Supports Ukraine
  • 3,612
  • 10
  • 26
  • 42
  • `s=l` is useless - s and l both point to the same data... see [how to copy/clone a list](https://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list) – Patrick Artner Jan 18 '19 at 22:11
  • there is no use for a nested loop - simply loop over `l`and add only stuff to `a` that is not in `del1` - remove each item that you did not copy over from del1 – Patrick Artner Jan 18 '19 at 22:12
  • 1
    He only wants to remove a single instance of things found in `del1`. Not every instance. – PMende Jan 18 '19 at 22:13
  • `else: pass` serves no purpose. You should delete it. – khelwood Jan 18 '19 at 22:17
  • 1
    @PatrickArtner My thoughts exactly. I improved on this by using a `collections.Counter` instance for `O(1)` lookup in `del1` (just for the sake of efficiency). – Joe Iddon Jan 18 '19 at 22:23

4 Answers4

4

You'll need to loop through the del list once:

lst= [1,5,10,5,10]
del1=[5,10]
res = lst[:]

for elem in del1:
    try:
        res.remove(elem)
    except ValueError:
        pass
res

Output: [1, 5, 10]

PMende
  • 5,171
  • 2
  • 19
  • 26
3

Your logic is confused, why are your iterating over the removal list, del1, and then within that iterating over s (or l).

This makes no sense.

Instead, just remove elements from del1, as you go.

l = [1,5,10,5,10]
del1 = [5,10]
a = []
for element in l:
   if element in del1:
       del1.remove(element)
   else:
       a.append(element)

giving a as [1, 5, 10].


A more efficient way is to use a collections.Counter object.

import collections
l = [1,5,10,5,10]
del1 = [5,10]
a = []
dels_to_go = collections.Counter(del1)
for element in l:
    if dels_to_go[element]:
        dels_to_go[element] -= 1
    else:
        a.append(element)

which gives the same output as before.


Note, you may be tempted to use a set(), but this would not work in the case of del1 containing repeated values.

Joe Iddon
  • 20,101
  • 7
  • 33
  • 54
0

If del1 does not contain duplicate items, you can make del1 a set for more efficient lookups, avoid appending items in l to a if the item is in the set, and remove the item from the set once it's been encountered:

del1 = set(del1)
a = []
for i in l:
    if i in del1:
        del1.remove(i)
        continue
    a.append(i)

a becomes:

[1, 5, 10]
blhsing
  • 91,368
  • 6
  • 71
  • 106
-1

Well, this solution would be a lot nicer if there was a way to return a list less the first occurrence of a given element.

def remove1(lst, elem):
  lst.remove(elem)
  return lst

cpy = lst[:]
res = [x for x in lst if x not in del1 or x in remove1(cpy, x)]

But this will not work if there are duplicate entries in del1. This would work,

res = [x for x in lst if x not in dlt or x in remove1(cpy, x) and x not in remove1(dlt, x)]

But it is getting ridiculous.

I guess I'll leave my answer up as evidence that a one liner is a bad idea for this problem.

okovko
  • 1,851
  • 14
  • 27