in reply to •Re: Keeping only the $n newest files/directories in a diretory?
in thread Keeping only the $n newest files/directories in a diretory?

I think this code is golfing at its best ;). It works but I don't understand it...

Could someone please explain the following part of merlyn's code:

my @newest_first = map $_->[0], sort { $a->[1] <=> $b->[1] } map [$_, -M], </var/script/proc/*>;

Thanks

  • Comment on Re: &bull;Re: Keeping only the $n newest files/directories in a diretory?
  • Download Code

Replies are listed 'Best First'.
Re: Re: &bull;Re: Keeping only the $n newest files/directories in a diretory?
by halley (Prior) on Apr 19, 2003 at 12:33 UTC
    The Schwartzian Transform is a technique to optimize the sorting of complex data structures in Perl.

    The simplest case would be to do a single line sort:

    my @newest_first = sort { -M $a <=> -M $b } </var/script/proc/*>;

    However, to sort, one must compare pairs of items, often comparing the same $a to many different $bs, and vice versa. All those -M checks take a lot of time.

    Read a Schwartzian Transform like this starting with the last line.

  • <.../*> is a shorthand call to glob() that returns a list of files.
  • The map above that takes each filename and pairs it to its own -M check results. So you get a list of "foo.blah", timestamp pairs. The square brackets keep each pair in their own little referenced array.
  • The sort line sorts these pairs numerically descending by their second (index 1) element, the timestamps.
  • The map at the top will turn the sorted list of pairs into a list of filenames again, keeping the sorted order.

    --
    [ e d @ h a l l e y . c c ]

      All those -M checks take a lot of time.

      On what antique system is that? Many simple filesystem operations are cached by the filesystem. System calls have overhead, but so does creating an array. And unless you have millions of files, you will probably not notice any difference in speed :)

      Juerd
      - http://juerd.nl/
      - spamcollector_perlmonks@juerd.nl (do not use).
      

Re: Re: &bull;Re: Keeping only the $n newest files/directories in a diretory?
by Improv (Pilgrim) on Apr 19, 2003 at 12:34 UTC
    Ok, reading it from the bottom up,
    </var/script/proc/*>
    Makes a list of files in that directory. It's then used as the second argument to
    map [$_, -M]
    which, from that list, generates a 2nd-order list, each element of which is a list containing in field one the filename, and in field two the modification time (-M is a test operator giving that -- it's default parameter is $_). If you're a C Programmer, think something like the following for each entry in that 2nd order list:
    struct { char filename[FNSIZE]; int mtime; /* The date field -- modification time */ }
    That structure is then used as an argument to
    sort { $a->[1] <=> $b->[1] }
    which sorts the first index of the 2nd-order list by the date field. The results are then used as the 2nd argument to
    map $_->[0]
    which returns a 1d list containing just the filenames (although they're sorted this time). The results are then saved in @newest_first. Code like the above can be intimidating unless you know the map operator well. It's an extremely powerful tool once you do though, and is one of the ways in which Perl's expressiveness borrows from Lisp. Hope this helps.
Re: Re: &bull;Re: Keeping only the $n newest files/directories in a diretory?
by Chady (Priest) on Apr 19, 2003 at 12:39 UTC

    That's the Schwartzian Transform. I goes something like this:

    </var/script/proc/*> will glob and return the list of file/directories in that folder.
    each element is mapped into an array ref[ ] containing the original string and the last modified date -M
    the list is sorted by the modification date which is the second element of the array ref, hence $a->[1]
    then the first element of the array (which is the original folder name) is retrieved $_->[0] with another map

    So in short, you get the list of folders, you build an array of arrays containing the folder name and the modification date, you sort by the modification date, and return only the folder names to use.

    Update: :)
    He who asks will be a fool for five minutes, but he who doesn't ask will remain a fool for life.

    Chady | http://chady.net/