CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Advanced:
How to sort this log file numerically.

 



sh.ajay12
User

Nov 7, 2012, 8:33 AM

Post #1 of 5 (7619 views)
How to sort this log file numerically. Can't Post

Hi All respected members,

I am having a log file.
Which has this type of content.

log.txt
<log_id = 12>
somelogs here
somelogs here
</log_id>

<log_id = 1>
somelogs here
somelogs here
</log_id>

<log_id = 14>
somelogs here
somelogs here
</log_id>

<log_id = 2>
somelogs here
somelogs here
</log_id>

The log file may contains log like this with any number.
I want to arrange the log_id and its content according to the numbers in increasing order, like this.

log.txt
<log_id = 1>
somelogs here
somelogs here
</log_id>

<log_id = 2>
somelogs here
somelogs here
</log_id>

<log_id = 12>
somelogs here
somelogs here
</log_id>

<log_id = 14>
somelogs here
somelogs here
</log_id>

I want the logs to be arranged in numerical order to a different file or the same file.

If it can be done, please tell me. Thank you.
Regards, Ajay Smile


BillKSmith
Veteran

Nov 7, 2012, 9:19 AM

Post #2 of 5 (7616 views)
Re: [sh.ajay12] How to sort this log file numerically. [In reply to] Can't Post

This approach only works if there is a blank line between every entry, and nowhere else. Minor changes may be needed for real data, but this should give you the idea.

Set the record separator to a blank line and slurp the file into an array. Use the "Schwartzian Transform" to sort the array.


Code
use strict; 
use warnings;
my @log;
do{ local $/ = "\n\n"; @log = <DATA>; };
@log = map {$_->[1]}
sort {$a->[0] <=> $b->[0]}
map {[/log_id = (\d\d?)/, $_]}
@log
;
print @log;
__END__

<log_id = 12>
somelogs here
somelogs here
</log_id>

<log_id = 1>
somelogs here
somelogs here
</log_id>

<log_id = 14>
somelogs here
somelogs here
</log_id>

<log_id = 2>
somelogs here
somelogs here
</log_id>

Good Luck,
Bill


sh.ajay12
User

Nov 7, 2012, 9:26 AM

Post #3 of 5 (7614 views)
Re: [BillKSmith] How to sort this log file numerically. [In reply to] Can't Post

Hi Bill,

thank you for the help.

I did not understand this part of the code.

do{ local $/ = "\n\n"; @log = <DATA>; };
@log = map {$_->[1]}
sort {$a->[0] <=> $b->[0]}
map {[/log_id = (\d\d?)/, $_]}
@log
;

Please explain if you have time.

Also please tell me list of books, from where I can read Perl and become a Perl programer like you.

Thanks


Laurent_R
Veteran / Moderator

Nov 7, 2012, 10:51 AM

Post #4 of 5 (7610 views)
Re: [sh.ajay12] How to sort this log file numerically. [In reply to] Can't Post

The


Code
map {$_->[1]} 
sort {$a->[0] <=> $b->[0]}
map {[/log_id = (\d\d?)/, $_]}


part is usually called a "Schwarzian Transform", look for this name on the Internet. You basically have to read this bottom up. The second map creates a list of arrays from your data (stored in @log), each array being composed of the log number and the data to be sorted, the sort sorts this array on the log number, and the first map extracts the original data from the list of arrays.


(This post was edited by Laurent_R on Nov 7, 2012, 10:54 AM)


BillKSmith
Veteran

Nov 7, 2012, 11:11 AM

Post #5 of 5 (7607 views)
Re: [sh.ajay12] How to sort this log file numerically. [In reply to] Can't Post


Code
use strict; 
use warnings;

These pragmas help us avoid common errors.


Code
my @log;

This declares a lexical array whose scope is the remainder of the file.


Code
do{ local $/ = "\n\n"; @log = <DATA>; };


The do{} is not really necessary. Its purpose is to limit the scope of the local declaration inside.

$/ is a perl special variable (refer: perldoc perlvar). It defines the separator between input records. It is defined as two newlines. The first is the last character of the previous line. The second is the only character in a blank line. Because of the do block, it is limited to this read only.

The second statement in the do block slurps (reads) the entire data file into the array, one record per array element. The entire file is read because the array puts the diamond operator in array context.


Code
@log = map {$_->[1]} 
sort {$a->[0] <=> $b->[0]}
map {[/log_id = (\d\d?)/, $_]}
@log
;

This is a single statement that sorts the array using a common perl idiom known as the “Schwartzian Transformation”. The idea is that it transforms the array into something that is easier to sort, sorts that and then extracts the sorted array. It is best understood starting from the end and working backwards. We want to sort the array @log. For each record in the array, The regular expression (refer: perdoc perlre) in map (refer perldoc -f map) extracts a one or two digit id. That and the original record become elements in a two element anonymous array. A reference to that array appended to a new list.
The list of references is sorted based on the first element of the arrays that they refer to.
The final map extracts the original records from the second element of each array in the order of the now sorted list. The new list of records now overwrites the original data in @logs. (Laurent is right. You can probably find a better explanation on the web. Watch for spelling variations)

Code
print @log;

This statement prints all the elements of @log.
Good Luck,
Bill

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives