Re: sorting entires by date
by Aristotle (Chancellor) on Jan 01, 2004 at 23:04 UTC
|
Basically you want a Schwartzian Transform. You parse the lines into a list of lists, sort it by the desired field, then extract the original data.
my @sorted =
map $_->[0]
sort { $a->[4] <=> $b->[4] }
map [ $_, split /:/ ],
<>;
Of course if you want to keep them around in the parsed form for later steps, you can leave out the copy of the line and the extraction step:
my @sorted =
sort { $a->[4] <=> $b->[4] }
map [ split /:/ ],
<>;
I am too lazy to explain the Schwartzian transform all over again :), so I Super Searched for some explaination. Surprisingly I came up empty for the time being..
The probably most important to understand parts are references and how to use them to create complex data structures in Perl. If you understand that, the Transform itself should be almost self-explanatory. Check out perldoc perlreftut, perldoc perldsc, and perldoc perllol.
Makeshifts last the longest.
| [reply] [d/l] [select] |
Re: sorting entires by date
by Coruscate (Sexton) on Jan 01, 2004 at 23:06 UTC
|
use Fcntl ':flock';
open my $fh, '+<', 'images.dat' or die "open failed: $!";
flock $fh, LOCK_EX;
seek $fh, 0, 0;
my @images;
while (<$fh>) {
chomp;
push @images, [(split /:/)[-1], $_];
}
my @ordered =
map { $_->[1] }
sort { $a->[0] <=> $b->[0] }
@images;
seek $fh, 0, 0;
truncate $fh, 0;
print $fh join "\n", @ordered;
close $fh;
Update: My brain isn't taking shortcuts today. I like Aristotle's approach of passing the file read directly to map(). Didn't think of it for some reason. So a slightly simplified version:
use Fcntl ':flock';
open my $fh, '+<', 'images.dat' or die "open failed: $!";
flock $fh, LOCK_EX;
seek $fh, 0, 0;
my @ordered =
map { $_->[1] }
sort { $a->[0] <=> $b->[0] }
map { chomp; [(split /:/)[-1], $_] }
<$fh>;
seek $fh, 0, 0;
truncate $fh, 0;
print $fh join "\n", @ordered;
close $fh;
| [reply] [d/l] [select] |
|
| [reply] |
|
| [reply] |
Re: sorting entires by date
by jweed (Chaplain) on Jan 01, 2004 at 23:15 UTC
|
If you want to sort a file by such a method, it would be best to read the file into an array (angle operator or Tie::File) and then use the Schwartzian Transform (read about it here) like this: @file = map { $$_[0] }
sort { $$a[1] <=> $$b[1] }
map { [$_, (split /:/)[3] ] } @file;
Hope that helps!
Update
Thought I'd make the ST clearer. Basically, you start with a map statement which takes every line in your file and puts it in an anonymous array with the timestamp (via split). Then, it passes an array with each of these to the sort routine, which sorts them based on the timestamp by getting that info from each anonymouss array in turn. Finally, the map statment at the end transforms this array of anonymous arrays back into an array with the lines from the file, properly sorted. Tada!
Update*2 You could also try a GRT, which might look something like this:@file = map { join ':', (split /:/)[1,2,3,0] }
sort
map { join ':', (split /:/)[3,0,1,2] } @file;
This has the clear limitation that it sorts asciibetically rather than numerically (doing it numerically might mitigate the benifits of GRT over ST, I'm not sure), which shouldn't be a problem really with time() but might be something to watch out for. Also, I'm sure this should have been done with pack or some such nonsense, but I don't know how. And finally, it may not even be faster. But, TMTOWTDI.
Who is Kayser Söze?
Code is (almost) always untested.
| [reply] [d/l] [select] |
Re: sorting entires by date
by exussum0 (Vicar) on Jan 01, 2004 at 23:09 UTC
|
#!/usr/bin/perl
use strict;
use warnings;
my %file = () ;
while(<>)
{
chop;
my( $file, $width, $height, $time ) = split(/:/);
$file{$time} = [ $file, $width, $height ];
}
foreach ( sort keys %file )
{
my $data = $file{$_};
print join(":", ( @$data, $_ ) ) . "\n";
}
Note, it doesn't work with files that have colons in them. I'm a big fan of letting the command line do stuff... so you'd run it ala..
script.pl < inFile > outFile
Play that funky music white boy..
| [reply] [d/l] [select] |
|
| [reply] [d/l] |
|
| [reply] |
Re: sorting entires by date
by pg (Canon) on Jan 01, 2004 at 23:18 UTC
|
First get your file into an array thru Tie::File, then:
use Data::Dumper;
my @a = ("image1.jpg:100:250:1062352538", "image2.jpg:650:175:10623403
+59");
@a = sort {(split(":", $a))[-1] <=> (split(":", $b))[-1]} @a;
print Dumper(\@a);
| [reply] [d/l] |
Re: sorting entires by date
by BrowserUk (Patriarch) on Jan 02, 2004 at 00:17 UTC
|
If, as your sample data indicates, your lines are of a consistant fixed format, then a simpler sort using substr would suffice.
my @sorted = sort{
substr( $a, 19 ) cmp substr( $b, 19 )
} <FILE>;
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
Hooray!
| [reply] [d/l] |
|
He has filenames in there, so assuming that the format is fixed is more than likely moot. But seeing as it is the last field we're interested, the following will work:
my @sorted = sort {
substr( $a, 1 + rindex, $a, ':' ) cmp substr( $b, 1 + rindex, $b,
+':' )
} <>;
Makeshifts last the longest.
| [reply] [d/l] |
|
| [reply] [d/l] |
|
| [reply] |
|
Re: sorting entires by date
by duff (Parson) on Jan 02, 2004 at 14:23 UTC
|
If you are on a unixish platform, there's the good 'ole sort command.
sort -n -t: -k4 filename
Remember, TMTOWTDI includes not using perl :-) | [reply] [d/l] [select] |