开发者

I can't seem to dereference an array correctly

开发者 https://www.devze.com 2023-03-08 02:14 出处:网络
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'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

  1. iterate over your array with array-references
  2. 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
}
0

精彩评论

暂无评论...
验证码 换一张
取 消