[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 95
  • Last Modified:

Perl sort question inside of a for loop

I'm trying to sort a list of data that I'm reading from a file and putting inside of an array. I want to sort the data by date and status.  I'm having trouble sorting because I think there's nothing to compare so it just spits it out as it's read.  I don't know if I need to pass the data somewhere first before I'm able to sort it or finish the loop then sort it. In any case, please help and let me know if you need more clarification.

Thanks!

.....

for my $i ("01" .. "30") {
        `download files`;
        open(my $fh, '< ', $download_path.'/'.$file.'-'.$i) or die("Could not open file $file-$i: $!.");

        while (my @row = <$fh>) {
                chomp @row;
                @arr = split ' ', $row[0];
        }

        my ($date, $path, $level, $num, $status) = @arr[2,4,7,8,9];
        my @pop_path = split '/', $first[4];
        my $title = $pop_path[3];
        my $day = UnixDate($date, "%Y-%m-%d %H:%M:%S");

        @sorted = (
        {
                date => $day,
                title => $title,
                path => $path,
                level => $level,
                num => $num,
                status => $status,
        }
        );

        @sorted = sort {
                $b->{date} cmp $a->{date}
        } @sorted;

        foreach my $line (@sorted){
                printf "%-22s %-15s %-4s %-2s %-5s %-30s\n" => @{$line}{qw(date title level num status path)};
        }

        close($fh);
}

.....
0
akatsuki27
Asked:
akatsuki27
  • 4
  • 4
  • 2
2 Solutions
 
Kim RyanIT ConsultantCommented:
As you are just using standard date stamps, you could use a simple utility such as 'sort' on linux or cygwin to do a multi column sort. Or import your file to something like Excel and do a multi column sort there.
0
 
FishMongerCommented:
Your code has a number of problems, but instead of rewriting your code I'll point you to a youtube video of a YAPC talk about the use of map, grep and sort.  The sort portion of the talk gives at least one example of sorting by date fields.
0
 
Kim RyanIT ConsultantCommented:
Can you supply a sample of your input file? I think this could be solved with a sort one-liner if that's any help.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
akatsuki27Author Commented:
Here's a sample of what's being read from the input:

20161113               title1       lev  1  comp  /some/path    
20161114               title2       lev  1  comp  /some/path  
20161115               title1       lev  2  comp  /some/path    
20161116               title1       lev  3  fail      /some/path

I want to be able to sort by date and then by status (5th column) if the date is the same. Does the sort need to be outside the loop or what?  I'm not an experienced coder, I just do small scripts like these for certain tasks so I'm sure there are probably cleaner ways to do this.
0
 
Kim RyanIT ConsultantCommented:
If you are on Unix type system, you could just do this
sort -k1 -k5 input.txt > sorted.txt
Assuming you have spaces between columns. Use the -t option to specify another field delimiter.
0
 
akatsuki27Author Commented:
If it's okay, can you suggest a solution using Perl? The sorting of the data is just one step to continue manipulating the data for another purpose. I just got stuck in that part of the script so I came here for some direction using Perl only, please.  Also, I'd rather not have to make too many system calls because I'm testing with a small amount of data.  Once the script is live, the amount of data processed will be huge and the script will be too taxing.  Btw, yes this will run on a *nix system.
0
 
FishMongerCommented:
Did your watch the youtube video I pointed you to?

Instead of manually writing the sorting code our selves as shown in the video, we could use one of the soting modules on cpan.
Sort::Fields
#!/usr/bin/perl

use warnings;
use strict;
use Sort::Fields;
use Data::Dumper;

chomp(my @unsorted = <DATA>);
my @sorted = fieldsort ['1n', 4], @unsorted;

print Dumper \@sorted;

__DATA__
20161114               title2       lev  1  comp  /some/path
20161113               title1       lev  1  comp  /some/path
20161116               title1       lev  3  fail  /some/path
20161115               title1       lev  2  comp  /some/path

Open in new window


c:\test>test.pl

$VAR1 = [
          '20161113               title1       lev  1  comp  /some/path',
          '20161114               title2       lev  1  comp  /some/path',
          '20161115               title1       lev  2  comp  /some/path',
          '20161116               title1       lev  3  fail  /some/path'
        ];

EDIT:
I didn't realize how old that module was (1998) until after I posted, so it's not the best choice, but it does work.  There are more up-to-date modules available, or you can write the sort code yourself, which is pretty easy.
0
 
akatsuki27Author Commented:
Thanks, FishMonger.  Honestly, I only saw part of the video since it was late at night and it's close to an hour.  I will check it out completely later though because I'm interested in learning more Perl.

But I was able to figure it out by writing it out myself. I pushed the incoming data into an array and sorted the array outside of the for loop. I put the print statement outside the loop also. Not pretty but it's working. The change in bold below:

....
        my @temp = (
        {
                date => $day,
                title => $title,
                path => $path,
                level => $level,
                num => $num,
                status => $status,
        }
        );

       foreach my $line (@temp){
                push (@sorted, $line);
        }


        close($fh);
}

@sorted = sort {  
        $a->{lnum} cmp $b->{num} ||
        $b->{date} <=> $a->{date}
} @sorted;

foreach my $sort (@sorted){
        printf "%-22s %-15s %-4s %-2s %-5s %-30s\n" => @{$sort}{qw(date title level num status path)};
}

.....
0
 
Kim RyanIT ConsultantCommented:
Glad you worked out a Perl solution. You can also use awk, it's well suited to this type of problem?
0
 
akatsuki27Author Commented:
I wasn't given a satisfactory answer before I figured it out on my own.
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

  • 4
  • 4
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now