0
list A: ['abc.txt', '123.txt', 'apple.jpg']

list B: ['ab', '123']

I want to generate a new list A that only contains the ones not in list B with wildcard match. The idea output will be:

list C: ['apple.jpg']

Here is my code:

lista=['abc.txt', 'happy.txt', 'apple.jpg']
listb=['happy', 'ab']
listc=lista

for a in lista:
    for b in listb:
        print(a + ": " + b)
        if b in a:
            listc.remove(a)

print(listc)

The output of my code is:

abc.txt: happy
abc.txt: ab
apple.jpg: happy
apple.jpg: ab
['happy.txt', 'apple.jpg']

Anyone know where it went wrong? And, any better way to do it? Tks.

stelioslogothetis
  • 9,371
  • 3
  • 28
  • 53
Minwu Yu
  • 311
  • 1
  • 6
  • 24
  • `listc=lista` does not accomplish anything, it just gives the data of lista another name ... whatfor? listc is the exact same data then a is, if you modify one you modify the other... – Patrick Artner May 29 '18 at 19:37
  • What does `wildcard` mean? Same prefix? Will `bc` exclude `abc.txt` as well? – kabanus May 29 '18 at 19:39
  • 3
    you probably need to copy elements like `listc = list(lista)` – Azat Ibrakov May 29 '18 at 19:39
  • @PatrickArtner, I want to save lista to a new listc, so when I make changes to listc, it won't affect lista. Not sure if I am doing the right way though – Minwu Yu May 29 '18 at 19:40
  • 1
    Possible duplicate of [How to clone or copy a list?](https://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list) – Patrick Artner May 29 '18 at 19:41
  • @kabanus, yes. if any partial string in listb found in lista, it will be something I need to delete – Minwu Yu May 29 '18 at 19:41
  • 1
    So your problem gets down to: you do not know how to copy a list. Fortunately there is a great question with answers for that. – Patrick Artner May 29 '18 at 19:41
  • @PatrickArtner, that solve my problem. Tks for troubleshooting. :) – Minwu Yu May 29 '18 at 19:49

4 Answers4

1

After the assignment listc=lista both variables refer to the same list. As a result, you modify the list through which you iterate, which causes the undesirable side effects. You should make a copy of the original list: listc=lista.copy().

Here's a better, regex-based solution to your problem:

import re
pattern = re.compile('|'.join(listb)) # Anything ON the listb
# re.compile('happy|ab')
listc = [a for a in lista if not pattern.match(a)]
# ['apple.jpg']
DYZ
  • 55,249
  • 10
  • 64
  • 93
0

You could use this list comprehension which filters the elements that don't exist in B (they aren't in any one of B's elements, and all B's elements aren't in them):

lista = ['abc.txt', '123.txt', 'apple.jpg']
listb = ['ab', '123']

listc = [a for a in lista if all(a not in b and b not in a for b in listb)]
print(listc) # => ['apple.jpg']
DjaouadNM
  • 22,013
  • 4
  • 33
  • 55
0

python as default copy list by reference. you need to make a deep copy from lista to listc. copy library can help you. modify your code like this:

    import copy
    lista=['abc.txt', 'happy.txt', 'apple.jpg']
    listb=['happy', 'ab']
    listc=copy.deepcopy(lista)

    for a in lista:
        for b in listb:
            if b in a:
                listc.remove(a)

     print(listc) 
Saeed Bolhasani
  • 552
  • 3
  • 15
  • There is no need for a deepcopy here. A shallow copy (`.copy()`) is sufficient. – DYZ May 29 '18 at 19:46
0

The problem is here :

listc = lista

You're copying the reference, not the content : so listc is lista. When you remove element from lista, listc is going to lose this element, too.

If you want to copy the content of the lista in listc, you need to use :

import copy
listc = copy.copy(lista)

You can get more informations here : How to clone or copy a list?

Victor
  • 602
  • 4
  • 12