in reply to Sorting a hash
A few things going on here. First, I added 'use strict', which will throw a bunch of errors around if anyone tries to use variables improperly. Next, I turned CLAIM_KEYS into a list of lists called @Claim_Fields. (I could have used a constant here, but one strange thing at a time.) Later on, I'm going to need to look up what type of sortings is needed on a given field, so I call get_table() to get a hash table. We'll define get_table() further down.use strict; use vars qw(@Claim_Fields %Claim_Table); @Claim_Fields = ( [ 'claim_batch_number', 'N', 'A8' ], [ 'claim_number', 'N', 'A6' ], [ 'claim_type', 'L', 'A2'], [ 'payment_direct', 'N', 'A2'], ); %Claim_Table = get_table();
Made some changes here. First, you had $data_file (formerly $DAT) and $sort_by hard-coded in your script. If you use @ARGV, you can specify them on the command line when you run the script. I added a '$!' to your die message on opening the data file, so that if it fails, it will print a more useful error message.Main: { my $data_file = $ARGV[0]; my $sort_by = $ARGV[1]; open(CLAIMS, $data_file) or die "CANNOT OPEN FILE: $!"; my @claim_records = (); while (<CLAIMS>) { push(@claim_records, read_record($_)); } close(CLAIMS);
Also, I moved your open and close out of subroutines, since it's good practice to close your handles in the same routine in which you opened them.
&Sort_File($sort_by, @claim_records); }
One of the things that was failing in your original script was that @claim_records wasn't getting passed to @sort_file. I turned $sort_by and @claim_records into arguments. Look at perlman:perlsub.
The first line reads $sort_by and @claim_records in as arguments. Then, we look at the %Claim_Table which we initialized at the top of the program and get the sort type. Next, we define an anonymous subroutine (see perlman:perlsub again) based on the 'L' or 'N' value in the table up top. If it's 'L', our subroutine will sort lexically, 'N' numerically. Well, it'll actually sort lexically if the value is anything other than 'N', but close enough.sub Sort_File { my ($sort_by, @claim_records) = @_; my $sort_sub; # If the sorting type is numeric if ( $Claim_Table{$sort_by} eq 'N' ) { # Create sub for numeric sort $sort_sub = sub { $a->{$sort_by} <=> $b->{$sort_by} }; } # End if numeric # Otherwise it's lexical else { # Create sub for lexical sort $sort_sub = sub { $a->{$sort_by} cmp $b->{$sort_by} }; } foreach my $record ( sort $sort_sub @claim_records ) { print STDOUT $record->{'claim_number'}, "\n"; } }
Finally, we close up with the original read_record() method, modified slightly to call the new get_fields() and get_template() subroutines. See perlman:perlref for more about handling lists of lists.
Anyway, that should get you out of the mess I put you into with my last post. :) Best of luck.sub read_record { my ($line) = @_; my %claim_record = (); @claim_record{ get_fields() } = unpack( get_template(), $line); return \%claim_record; } ## ## Returns all of the field names in @Claim_Fields ## sub get_fields { my @fields = (); foreach my $claim_field ( @Claim_Fields ) { push(@fields, $claim_field->[0]); } return @fields; } ## ## Builds the template from the template fields in @Claim_Fields ## sub get_template { my $template = ''; foreach my $claim_field ( @Claim_Fields ) { $template .= $claim_field->[2]; } return $template; } ## ## Builds a hash table for lookup from @Claim_Fields ## sub get_table { my %table = (); foreach my $claim_field ( @Claim_Fields ) { $table{$claim_field->[0]} = $claim_field->[1]; } return %table; }
stephen
|
|---|