6

I'm really new to Python, only working on it, as another guy in my team left and need to get some work over the line, so apologies if this is a stupid question.

I need to remove items from a list (they'll contain a certain phrase) and have googled and tried a few ways but it doesn't seem to be working.

What I've currently got is,

def get_and_count_card_files(date):
    # Retrieve the DC and SD card files
    dc_files = dc_card_files.get_dc_files(dc_start_location, date)
    sd_files = sd_card_files.get_sd_files(sd_start_location)
    print(dc_files)

if '*NoCover*' in dc_files:
    dc_files.remove('*NoCover*')

Dc_files being the list (bunch of file names) and I need to remove anything that has NoCover in the file name. It does exist as the print function shows me it does.

Anyone any idea what I'm doing wrong

enter image description here

Vinz
  • 5,997
  • 1
  • 31
  • 52
titan31
  • 185
  • 4
  • 17
  • 1
    You should never remove elements from a list you are iterating over. http://stackoverflow.com/questions/1207406/remove-items-from-a-list-while-iterating-in-python – Padraic Cunningham Sep 21 '15 at 10:49
  • Ideally the file I'm removing would never be created in the first place, but it is, so need to get rid of it, as the script later zips up the files, and I don't want to be put in there – titan31 Sep 21 '15 at 10:58

4 Answers4

8

With this piece of code, the * won't do a glob or regular expression in these contexts:

if '*NoCover*' in dc_files:
    dc_files.remove('*NoCover*')

so it would be better to say:

if 'NoCover' in dc_files:

However, we then have to find the right entry to remove in the list, without using wildcards.

For a small list, you could iterate over it. A list comprehension would do:

new_dc_files = [dc for dc in dc_files if 'NoCover' not in dc]

It's a compact way of saying:

new_dc_files = list()
for dc in dc_files:
    if 'NoCover' in dc:
         continue
    new_dc_files.append(dc)
Simon Fraser
  • 2,758
  • 18
  • 25
0

if '*NoCover*' in dc_files: will look for an element in the list dc_files that matches, explicitly to 'NoCover'.

What you can do, is

# Iterate over the list backwards, this will stop you from skipping elements
# you want to check in the next iteration if you remove something
for index, dc_file in enumerate(dc_files[::-1]):
    if 'NoCover' in dc_file:
        dc_files.pop(index)

Alternatively, you can look at using regular expressions if you have more complex pattern matching requirements.

Christian Witts
  • 11,375
  • 1
  • 33
  • 46
  • `ValueError: too many values to unpack` - perhaps you meant `enumerate(dc_files[::-1])` ? However, this also modifies the list you're iterating over, which can cause interesting errors. – Simon Fraser Sep 21 '15 at 10:30
  • I corrected it to include the enumerate. The reason you step backwards, using the `[::-1]` syntax is to avoid the list mutation issues that are present when forward iterating and mutating. – Christian Witts Sep 21 '15 at 10:31
  • I did get an `IndexError: pop index out of range` when running it against a test array. Marco's answer does work, thoguh, when I'd expected it not to, so perhaps I don't understand iteration as well as I thought! – Simon Fraser Sep 21 '15 at 10:33
  • Also, this is not correct, `enumerate(dc_files[::-1])` - also spits out indexes from `0` so if the last element matched you would end up removing the first element. – Anand S Kumar Sep 21 '15 at 10:41
0

You could use a Python list comprehension to filter out the unwanted entries:

def get_and_count_card_files(date):
    # Retrieve the DC and SD card files
    dc_files = dc_card_files.get_dc_files(dc_start_location, date)
    sd_files = sd_card_files.get_sd_files(sd_start_location)

    print(dc_files)
    dc_files = [file for file in dc_files if 'NoCover' not in file]
Martin Evans
  • 45,791
  • 17
  • 81
  • 97
0

You are looking for Python's list comprehension:

dc_files = [el for el in dc_files if 'NoCover' not in el]

So what this basically does is filter all the elements from dc_files that do not contain the 'NoCover' string.

Note, that if 'NoCover' not in el is executed for each element of the list, and the in operator for a string simply checks exactly what you wanted to do, i.e. whether 'NoCover' is a substring of el.

Community
  • 1
  • 1
bagrat
  • 7,158
  • 6
  • 29
  • 47