Fuji Komalan
Fuji Komalan

Reputation: 2047

Removing some elements from a list which satisfy some condition

I have a list with some file names(locations), what I am trying to do is I want to remove every elements from the list locations.

Condition: do not print the file name if it starts with the any of the strings in the excludes list.

locations = ['/data/mybackup/data/fil1',
            '/data/mybackup/data/fil2', 
            '/data/mybackup/data/fil3', 
            '/data/mybackup/song/fil1', 
            '/data/mybackup/song/fil2',
            '/data/mybackup/song/fil3', 
            '/data/archive/song/fil1', 
            '/data/archive/song/fil2', 
            '/data/archive/song/fil3', 
            '/data/archive/data/fil1', 
            '/local/archive/data/fil2', 
            '/local/archive/data/fil3',
            '/ebboks/wordpress/fil1', 
            '/ebooks/wordpress/fil2', 
            '/ebooks/wordpress/fil3']

excludes = [  '/data/archive/', '/data' , '/ebooks/'   ]

for location in locations:
  for exclude in excludes:
    if not location.startswith(exclude):
      print(location)
    break      

RESULT:

/data/mybackup/data/fil1
/data/mybackup/data/fil2
/data/mybackup/data/fil3
/data/mybackup/song/fil1
/data/mybackup/song/fil2
/data/mybackup/song/fil3
/local/archive/data/fil2
/local/archive/data/fil3
/ebboks/wordpress/fil1
/ebooks/wordpress/fil2
/ebooks/wordpress/fil3     

My result still have the file names starting with '/data'

What is wrong with my code?

Upvotes: 2

Views: 99

Answers (6)

Wizard
Wizard

Reputation: 22093

try list comprehensions:

>>> [location for location in locations \
if not location.startswith(tuple(excludes))]

output:

['/local/archive/data/fil2', '/local/archive/data/fil3', '/ebboks/wordpress/fil1']

or filter with lambdas if you prefer functional programming in answer of @mshsayem

Upvotes: 0

mshsayem
mshsayem

Reputation: 18008

Because you are checking against /data/archive/ first; it is letting all entries which are not starting with /data/archive/ essentially skipping the check for /data.

You can do this:

>>> excludes = tuple(excludes)
>>> filter(lambda x: not x.startswith(excludes), locations)
['/local/archive/data/fil2', '/local/archive/data/fil3', '/ebboks/wordpress/fil1']

Upvotes: 1

Jon Clements
Jon Clements

Reputation: 142156

str.startswith accepts a tuple of arguments to check against so you avoid an additional loop to check and concerns about ordering comparisons, so you can use:

exc = tuple(excludes)
# Or start with: excludes = ('/data/archive/', '/data' , '/ebooks/') instead
for location in locations:
    if not location.startswith(exc):
        print(location)

Which gives you:

/local/archive/data/fil2
/local/archive/data/fil3
/ebboks/wordpress/fil1

Upvotes: 3

RomanPerekhrest
RomanPerekhrest

Reputation: 92854

Condition: do not print the file name if it starts with the any of the strings in the excludes list.

With all() function:

for location in locations:
    if all(not location.startswith(e) for e in excludes):
        print(location)

The output:

/local/archive/data/fil2
/local/archive/data/fil3
/ebboks/wordpress/fil1

Upvotes: 3

bassman
bassman

Reputation: 195

For location is , let's say, "/data/mybackup/data/fil1" and exclude is "/data/archive", the location variable doesn't start with "/data/archive".

As you have a "/data" value in your excludes list, you don't need to put another path that starts with "/data". So if you define excludes = ["/data", "/ebooks"] there will be no problem.

Upvotes: 2

Paweł Tatarczuk
Paweł Tatarczuk

Reputation: 646

You have to check all excludes before printing the location.

Try changing this:

for location in locations:
  for exclude in excludes:
    if not location.startswith(exclude):
      print(location)
    break   

To:

def valid(location):
  for exclude in excludes:
    if location.startswith(exclude):
      return False
  return True

for location in locations:
  if valid(location):
    print(location)

Upvotes: 1

Related Questions