[Newby question] List comprehension

Discussion in 'Python' started by Eelco Hoekema, Aug 6, 2004.

  1. 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
     
    Eelco Hoekema, Aug 6, 2004
    #1
    1. Advertisements

  2. Eelco Hoekema

    Tom B. Guest

    os.walk(os.path.abspath('.')) if filter(song, files)]
    How about,

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

    Tom
     
    Tom B., Aug 6, 2004
    #2
    1. Advertisements

  3. Eelco Hoekema

    Larry Bates Guest

    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.

    os.walk(os.path.abspath('.')) if filter(song, files)]
     
    Larry Bates, Aug 6, 2004
    #3
  4. Larry Bates 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)]

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

    eelco
     
    Eelco Hoekema, Aug 6, 2004
    #4
  5. 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.
     
    Christopher T King, Aug 6, 2004
    #5
  6. Eelco Hoekema schreef:
    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
     
    Eelco Hoekema, Aug 6, 2004
    #6
  7. 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
     
    Skip Montanaro, Aug 6, 2004
    #7
  8. Skip Montanaro schreef:
    song() does return True or False, but the return value is used in the
    filter, which returns a list.
    That would yield a list of tuples of directories that contain at least one
    song. Could still be of use.

    eelco
     
    Eelco Hoekema, Aug 6, 2004
    #8
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.