Home     |     .Net Programming    |     cSharp Home    |     Sql Server Home    |     Javascript / Client Side Development     |     Ajax Programming

Ruby on Rails Development     |     Perl Programming     |     C Programming Language     |     C++ Programming     |     IT Jobs

Python Programming Language     |     Laptop Suggestions?    |     TCL Scripting     |     Fortran Programming     |     Scheme Programming Language


 
 
Cervo Technologies
The Right Source to Outsource

MS Dynamics CRM 3.0

Perl Programming Language

sort?


Greeting:

I have the following code to sort an array of dirs/files:

    @sorted = sort { -M $b <=> -M $a } @logfile;
    foreach $lastfilemod (@sorted) {
        $dir = (dirname $lastfilemod);
        if (! exists $srt{$dir} ) {
            push(@srtlist, $lastfilemod);
            $srt{$dir} = 1;
        }
    }

The @logfile looks like:

/dir/dir/file1
/dir/dir/file2
/dir/dir2/file1
...

What I was trying to do is have @sorted list the files by last
modified and then I could print out each file last modified in one per
directory. However the sort isn't working correctly and I'm not
getting the last file modified for some directories. Could anyone
point out what I'm doing wrong?

Thanks in advance for any help!

  Tom

On May 24, 6:02 pm, g41@motorola.com wrote:

Have you checked that the values of the entries in @logfile are
actually the _exact_ names of files that exist and that you have
permission to read the attributes of? Are you sure that, for example,
you don't have newline characters appended?

I'd to a transform and check -M worked.

my @sorted =
  map { $_->[0] }
  sort { $b->[1] <=> $a->[1] }
 @logfile;

On May 24, 6:32 pm, Brian McCauley <nobul@gmail.com> wrote:

Opps hit send before I finished typing...

# Untested
my @sorted =
  map { $_->[0] }
  sort { $b->[1] <=> $a->[1] }
  map {
    my $mod = -M;
    if ( defined $mod ) {
       [ $_, $mod ];
    else {
       warn "$_: $!\n";
       ();
    }
  } @logfile;

On May 24, 1:02 pm, g41@motorola.com wrote:

I think you have your sort backwards, for one.  -M returns the number
of days since the file was modified.  You're sorting the resutls of -M
in descending numerical order.  That is, largest first.  So the file
with the LARGEST number of days since it was modified comes first.
The file with the largest number of days since modification is the
least recently modified, not most recently.

Once you get this working, I also rather strongly suggest you not use
the file-comparison operators in a sort subroutine. It's very
ineffient, as you're doing a stat() call on every file in your list
multiple times.  Instead, use a Schwartzian transform:

my @sorted = map { $_->[0] }
            sort { $a->[1] <=> $b->[1] }
             map { [ $_, -M $_ ] } @logfile;

Paul Lalli

In article <1180026173.627588.321@q75g2000hsh.googlegroups.com>,
     <g41@motorola.com> wrote:

: I have the following code to sort an array of dirs/files:
:
:     @sorted = sort { -M $b <=> -M $a } @logfile;
:     foreach $lastfilemod (@sorted) {
:         $dir = (dirname $lastfilemod);
:         if (! exists $srt{$dir} ) {
:             push(@srtlist, $lastfilemod);
:             $srt{$dir} = 1;
:         }
:     }
:
: The @logfile looks like:
:
: /dir/dir/file1
: /dir/dir/file2
: /dir/dir2/file1
: ...
:
: What I was trying to do is have @sorted list the files by last
: modified and then I could print out each file last modified in one per
: directory. However the sort isn't working correctly and I'm not
: getting the last file modified for some directories. Could anyone
: point out what I'm doing wrong?

For each file, remember it if it was modified more recently than the
current frontrunner for the file's parent directory:

    $ cat try
    #! /usr/bin/perl

    use warnings;
    use strict;

    use File::Basename;

    sub filename { $_[0]->[0] }
    sub modified { $_[0]->[1] }

    my %last;

    for (`find /tmp -type f 2>/dev/null`) {
      chomp;

      my $dir = dirname $_;
      my $mod = -M $_;

      $last{$dir} = [ basename($_), $mod ]
        if !$last{$dir} || $mod > modified $last{$dir};
    }

    foreach my $dir (sort keys %last) {
      print "$dir: ", filename($last{$dir}), "\n";
    }

    $ ./try
    /tmp: sh-thd-1172576387
    /tmp/exportfig: restorefig.m
    /tmp/shared: .Xdefaults
    /tmp/split-sequence: split-sequence.lisp

Hope this helps,
Greg
--
The idea that the vote of a people, no matter how nearly unanimous, makes or
creates or determines what is right or just becomes as absurd and
unacceptable as the idea that right and justice are simply whatever a king
says they are.             -- Robert Welch

Hi All:

Thanks for all the responces! I found that -M doesn't give the
granularity I needed. Some of the files were only seconds away for the
other. I changed to the following:

use File::stat;
    @sorted = sort { (stat($b)->mtime) <=> (stat($a)->mtime) }
@logfile;
    foreach $lastfilemod (@sorted) {
        $dir = (dirname $lastfilemod);
        if (! exists $srt{$dir} ) {
            push(@srtlist, $lastfilemod);
            $srt{$dir} = 1;
        }
    }

Hi All:

Thanks for all the responces! I found that the -M doesn't give the
granularity I need. Some of the files were only seconds apart. I
changed to the following:

    use File::stat;
    @sorted = sort { (stat($b)->mtime) <=> (stat($a)->mtime) }
@logfile;
    foreach $lastfilemod (@sorted) {
        $dir = (dirname $lastfilemod);
        if (! exists $srt{$dir} ) {
            push(@srtlist, $lastfilemod);
            $srt{$dir} = 1;
        }
    }

This got just what I was looking for. Thanks again for all the replys!

Tom

On May 24, 2:28 pm, g41@motorola.com wrote:

> Thanks for all the responces! I found that -M doesn't give the
> granularity I needed.

I'm sorry, what?!

[14:43:46] ~/tmp $ touch file.txt
[14:43:52] ~/tmp $ perl -le'print -M "file.txt"'
0.000115740740740741

Exactly how much more granularity do you need?!

Paul Lalli

Some of the files were only seconds away for the

> other. I changed to the following:

> use File::stat;
>     @sorted = sort { (stat($b)->mtime) <=> (stat($a)->mtime) }
> @logfile;

The reason this works and your other one didn't is because you're now
comparing the last modified times as seconds sine the epoch, not days
since last modified.  So NOW, your descending numerical sort is
correct.  The file with the greatest seconds since the epoch is in
fact the most recently modified.  Compare and contrast with the file
with the greatest days since last modified. *

If you had just swapped $a and $b in your original, it would have been
fine.

Paul Lalli

* Here's an example.  Presuming we're running at 14:55:00 on May 24,
2007....
file1 - last modified Jan 1, 1970 00:00:00
file2 - last modified May 23, 2007, 14:55:00
file3 - last modified May 24, 2007, 14:55:00

-M file1 returns 13657.7849421296
-M file2 returns 1
-M file3 returns 0

stat(file1)->mtime returns 0
stat(file2)->mtime returns 1179946500
stat(file3)->mtime returns 1180032900

Do you see now what you did wrong the first time?

g41@motorola.com wrote:
> Hi All:

> Thanks for all the responces! I found that the -M doesn't give the
> granularity I need. Some of the files were only seconds apart.

So what, pray tell, do you think -M actually returns?
It is _NOT_ the integer number of days of age.

Proof that -M has all the granularity you need:

linux% foreach n (0 1 2 3)
foreach? touch -d "2-Jan-1970 12:00:0$n" $n
foreach? end
linux% ls -l ?
-rw-r--r--  1 jms jms 0 Jan  2  1970 0
-rw-r--r--  1 jms jms 0 Jan  2  1970 1
-rw-r--r--  1 jms jms 0 Jan  2  1970 2
-rw-r--r--  1 jms jms 0 Jan  2  1970 3
linux% perl -le 'print "file $_ has -M = ", -M $_ for @ARGV' ?
file 0 has -M = 13661.9331481481
file 1 has -M = 13661.9331365741
file 2 has -M = 13661.933125
file 3 has -M = 13661.9331134259
  1/(24*60*60) =     0.00001157407

Where did you come up with the idea that -M is not suitable?
        -Joe

Add to del.icio.us | Digg this | Stumble it | Powered by Megasolutions Inc