[Newby question] List comprehension

E

Eelco Hoekema

I'm trying to get a list of tuples, with each tuple consisting of a
directory, and a list of files. I only want a tuple if and only if the
filtered list of files is not empty. And, i want the list of files in the
tuples to be filtered. For this, i came up with the following code:

<code>

# song filter: will return true if the file seems to be an mp3 file.
# (may not be the best way to do this)
def song(f):
(name, ext) = os.path.splitext(f)
return ext.lower() == '.mp3'

# list comprehension walking through a directory tree
[(root, filter(song, files)) for (root, dir, files) in os.walk(os.path.abspath('.')) if filter(song, files)]


</code>

Now, this will work. However, it seems kind of silly to call the filter
twice. Is there a way to keep this in one list comprehension, but with
just filtering once?

eelco
 
T

Tom B.

Eelco Hoekema said:
I'm trying to get a list of tuples, with each tuple consisting of a
directory, and a list of files. I only want a tuple if and only if the
filtered list of files is not empty. And, i want the list of files in the
tuples to be filtered. For this, i came up with the following code:

<code>

# song filter: will return true if the file seems to be an mp3 file.
# (may not be the best way to do this)
def song(f):
(name, ext) = os.path.splitext(f)
return ext.lower() == '.mp3'

# list comprehension walking through a directory tree
[(root, filter(song, files)) for (root, dir, files) in
os.walk(os.path.abspath('.')) if filter(song, files)]
</code>

Now, this will work. However, it seems kind of silly to call the filter
twice. Is there a way to keep this in one list comprehension, but with
just filtering once?

eelco
How about,

fltres = filter(song, files)
[(root, fltres ) for (root, dir, files) in os.walk(os.path.abspath('.')) if
fltres]

Tom
 
L

Larry Bates

Actually I think (??) this is better done in a loop:
(not tested)

toc=[]
for root, dir, files in os.walk(os.path.abspath('.')):
mp3files=[f for f in files if f.lower().endswith('.mp3')]
if mp3files: toc.append((root, mp3files))


HTH,
Larry Bates
Syscon, Inc.

Eelco Hoekema said:
I'm trying to get a list of tuples, with each tuple consisting of a
directory, and a list of files. I only want a tuple if and only if the
filtered list of files is not empty. And, i want the list of files in the
tuples to be filtered. For this, i came up with the following code:

<code>

# song filter: will return true if the file seems to be an mp3 file.
# (may not be the best way to do this)
def song(f):
(name, ext) = os.path.splitext(f)
return ext.lower() == '.mp3'

# list comprehension walking through a directory tree
[(root, filter(song, files)) for (root, dir, files) in
os.walk(os.path.abspath('.')) if filter(song, files)]
 
E

Eelco Hoekema

Larry Bates schreef:
Actually I think (??) this is better done in a loop:
(not tested)

toc=[]
for root, dir, files in os.walk(os.path.abspath('.')):
mp3files=[f for f in files if f.lower().endswith('.mp3')]
if mp3files: toc.append((root, mp3files))

That is about the same as Facundo Bastida said. But then, i like this
better:

tmp = [(root, files) for (root, dir, files) in os.walk(os.path.abspath('.')) if files]
toc = [(root, files) for (root, files) tmp if filter(song, files)]

But that means 2 list comprehensions. Ans i'm just wondering if it can be
done in one, without filtering twice.

eelco
 
C

Christopher T King

[(root, filter(song, files)) for (root, dir, files) in
os.walk(os.path.abspath('.')) if filter(song, files)]

Now, this will work. However, it seems kind of silly to call the filter
twice. Is there a way to keep this in one list comprehension, but with
just filtering once?

You may do best to split this into two LCs:

temp = [(root, filter(song,files)) for (root, dir, files) in
os.walk(os.path.abspath('.'))]
temp = [(root, songs) for (root, songs) in temp if songs]

Or if you prefer, replace the latter with:
temp = filter(temp, lambda x: x[1])

Or even, in 2.4:
temp = filter(temp, itemgetter(1))

In 2.4, you will also be able to replace the first LC with a generator
expression, saving a bit of both memory and processor time (the change
would consist of replacing the brackets with parentheses).

Hope this helps.
 
E

Eelco Hoekema

Eelco Hoekema schreef:
That is about the same as Facundo Bastida said. But then, i like this
better:
tmp = [(root, files) for (root, dir, files) in os.walk(os.path.abspath('.')) if files]
toc = [(root, files) for (root, files) tmp if filter(song, files)]

Hmm. That doesn't work. It's the other way around, like Christoffer
King showed:

tmp = [(root, files) for (root, dir, files) in os.walk(os.path.abspath('.')) if filter(song, files)]
toc = [(root, files) for (root, files) tmp if files]

eelco
 
S

Skip Montanaro

Eelco> # song filter: will return true if the file seems to be an mp3 file.
Eelco> # (may not be the best way to do this)
Eelco> def song(f):
Eelco> (name, ext) = os.path.splitext(f)
Eelco> return ext.lower() == '.mp3'

Eelco> # list comprehension walking through a directory tree
Eelco> [(root, filter(song, files)) for (root, dir, files) in os.walk(os.path.abspath('.')) if filter(song, files)]

In this particular case, since song() only returns True or False, you could
use

[(root, True) for (root, dir, files) in os.walk(os.path.abspath('.'))
if filter(song, files)]

Skip
 
E

Eelco Hoekema

Skip Montanaro schreef:
Eelco> # list comprehension walking through a directory tree
Eelco> [(root, filter(song, files)) for (root, dir, files) in os.walk(os.path.abspath('.')) if filter(song, files)]
In this particular case, since song() only returns True or False,

song() does return True or False, but the return value is used in the
filter, which returns a list.
you could use
[(root, True) for (root, dir, files) in os.walk(os.path.abspath('.'))
if filter(song, files)]

That would yield a list of tuples of directories that contain at least one
song. Could still be of use.

eelco
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top