[Newby question] List comprehension

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Eelco Hoekema

    [Newby question] List comprehension


    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.splitex t(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


  • Tom B.

    #2
    Re: [Newby question] List comprehension


    "Eelco Hoekema" <eelco.usenet@x s4all.nl> wrote in message
    news:pan.2004.0 8.06.13.22.50.7 5041@xs4all.nl. ..[color=blue]
    >
    > 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.splitex t(f)
    > return ext.lower() == '.mp3'
    >
    > # list comprehension walking through a directory tree
    > [(root, filter(song, files)) for (root, dir, files) in[/color]
    os.walk(os.path .abspath('.')) if filter(song, files)][color=blue]
    >
    >
    > </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
    >
    >[/color]
    How about,

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

    Tom


    Comment

    • Larry Bates

      #3
      Re: [Newby question] List comprehension

      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().endsw ith('.mp3')]
      if mp3files: toc.append((roo t, mp3files))


      HTH,
      Larry Bates
      Syscon, Inc.

      "Eelco Hoekema" <eelco.usenet@x s4all.nl> wrote in message
      news:pan.2004.0 8.06.13.22.50.7 5041@xs4all.nl. ..[color=blue]
      >
      > 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.splitex t(f)
      > return ext.lower() == '.mp3'
      >
      > # list comprehension walking through a directory tree
      > [(root, filter(song, files)) for (root, dir, files) in[/color]
      os.walk(os.path .abspath('.')) if filter(song, files)][color=blue]
      >
      >
      > </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
      >
      >[/color]


      Comment

      • Eelco Hoekema

        #4
        Re: [Newby question] List comprehension

        Larry Bates schreef:
        [color=blue]
        > 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().endsw ith('.mp3')]
        > if mp3files: toc.append((roo t, mp3files))[/color]

        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

        Comment

        • Christopher T King

          #5
          Re: [Newby question] List comprehension

          On Fri, 6 Aug 2004, Eelco Hoekema wrote:
          [color=blue]
          > [(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?[/color]

          You may do best to split this into two LCs:

          temp = [(root, filter(song,fil es)) 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.

          Comment

          • Eelco Hoekema

            #6
            Re: [Newby question] List comprehension

            Eelco Hoekema schreef:
            [color=blue]
            > That is about the same as Facundo Bastida said. But then, i like this
            > better:[/color]
            [color=blue]
            > 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)][/color]

            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

            Comment

            • Skip Montanaro

              #7
              Re: [Newby question] List comprehension

              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.splitex t(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

              Comment

              • Eelco Hoekema

                #8
                Re: [Newby question] List comprehension

                Skip Montanaro schreef:
                [color=blue]
                > 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)][/color]
                [color=blue]
                > In this particular case, since song() only returns True or False,[/color]

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

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

                eelco

                Comment

                Working...