I'm not very adept at Perl, but I need to be able to do a s开发者_如何学Pythonort on a multi-dimension array. I've been playing with some test code to try and get a better grasp on the concept, and I think I'm getting close, but I can't find the magic combination.
What I can't seem to do is dereference my arrays and get them to print correctly. I can seem to get just about everything in the world I need to know about these refrences except for the values in the arrays being referenced.
I'm getting my data from a tab-delimited flat file, so in my sample code, I'm mimicking that by creating multiple arrays via splits and then pushing them in to a single array. In practice, I'll be looping through the file, splitting on the tabs and pushing them in to the array as I go.
If there is a better way of going about this, I'm all ears. Each line in the flat file is a single record. I need to first sort by a date to get the oldest records to the top, and then do a secondary sort to group records by acct number. I've looked at several examples online, but not found anything that seems to work with the data I need to mimick.
my @s1 = split(/:/, 'X:Y:Z');
my @s2 = split(/:/, 'A:B:C');
my @s3 = split(/:/, 'Q:L:P:0');
my @s4 = split(/:/, 'U:E:G');
my @array = ();
push(@array, \@s1);
push(@array, \@s2);
push(@array, \@s3);
push(@array, \@s4);
print "@array\n";
my @sorted = sort { $a->[0] cmp $b->[0] } @array;
print "\n";
foreach $thingy (@sorted)
{
print @thingy . "\n"; #result: number 0
print $thingy . "\n"; #result: reference
#print ${$thingy} . "\n"; #result: 'Not a scalar reference' error
print ${@thingy} . "\n"; #result: file name (???)
print @{$thingy} . "\n"; #result: length of the array referenced
}
First of all, you should always put use strict;
at the top of your program. That will catch numerous errors early.
The last line in your foreach
loop is the one that dereferences $thingy
correctly. But since you've put @{$thingy}
on the left-hand side of the .
(string concatenation) operator, the array is in scalar context, and arrays in scalar context evaluate to their size. Just say:
print "@{$thingy}\n";
to get the elements of @$thingy
separated by spaces, or in general
print join('|', @{$thingy}), "\n";
if you want to use another separator, like the vertical bar character. You can also just say
print @{$thingy}, "\n";
to print the elements with no separator at all.
@thingy
is undeclared and undefined (and unnecessary).
Use two nested loops to
- iterate over your array with array-references
- and in each loop then iterate over the items in that referenced array.
Like this
foreach my $array_ref (@sorted)
{
foreach my $item (@{$array_ref}) {
print $item, ",";
}
print "\n";
}
The expression @{$array_ref}
will dereference your array reference. It is used like an array then.
Addition:
You could replace
my @s1 = split(/:/, 'X:Y:Z');
my @s2 = split(/:/, 'A:B:C');
my @s3 = split(/:/, 'Q:L:P:0');
my @s4 = split(/:/, 'U:E:G');
my @array = ();
push(@array, \@s1);
push(@array, \@s2);
push(@array, \@s3);
push(@array, \@s4);
with
my @array = ();
push(@array, map { [split(/:/, $_)] } qw(X:Y:Z A:B:C Q:L:P:0 U:E:G));
If the sorting needs two criteria (the primary one at the first index and the secondary one at the second index) it can be written like this:
my @sorted = sort { $a->[0] cmp $b->[0]
||
$a->[1] cmp $b->[1]
} @array;
The first thing you need to do is add this to your script:
use strict;
use warnings;
Then you will get the warning:
Global symbol "@thingy" requires explicit package name
Which means that @thingy
is not defined. In perl, $thingy
and @thingy
count as separate variables.
Another way to create your array is to use anonymous arrays, like this:
push @array, [ split(/:/, 'X:Y:Z') ];
push @array, [ split(/:/, 'A:B:C') ];
...
Then you won't have to create throwaway variables. Or with a file like the one you describe (\t
is tab):
while (<>) {
push @array, [ split /\t/, $_ ];
}
A way to sort on multiple columns, from perlmonks:
my @a = ([1,2], [3,4]);
my @b = sort {
$a->[0] <=> $b->[0] || # the result is -1,0,1 ...
$a->[1] <=> $b->[1] # so [1] when [0] is same
} @a;
http://www.perlmonks.org/index.pl?node_id=674374
Of course, this assumes numerical values in your fields. Otherwise use cmp
.
To print:
for my $ref (@array) {
my $i = 0;
for my $value (@$ref) {
print $value;
print "," if ($i++ < $#$ref); # comma delimited
}
print "\n"; # end of record
}
精彩评论