Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

arg! somewhat complicated mixed datastructures!

Status
Not open for further replies.

m4trix

Vendor
Jul 31, 2002
84
CA
I'm sure this is simple, but I can't seem to align my thoughts right.

I have a file that I'm reading into an array with a series of values. For the sake of arguement we'll say there's three numbers, then any number of other numbers.

I want to store the first three numbers separately, and then the rest as an array.
[tt]
my ($s1, $s2, $s3, @a) = split(/\s/, $_);
[/tt]
works quite happily within a while (<F>) loop.
the next line sticks that stuff into an array of hashes (each index of the array represents the line number essentially)
[tt]
push (@lines, {sc1 => $s1, sc2 => $s2, sc3 => $s3, arr => \@a});
[/tt]
and also seems to work quite fine. all the data can be accessed easily through
[tt]
$lines[idx]{sc1}
$lines[idx]{sc2}
$lines[idx]{sc3}
$lines[idx]{arr}[0] to $lines[idx]{arr}[n]
[/tt]

Ok, all that works fine. Here's the part I'm stuck at.
Occasionally I want to shift one of those array elements off. Through experimentation, it seems that shift returns a reference to the array element. right?
[tt]
$lineref = shift(@lines);
[/tt]
now I want information added into a NEW array of hashes. The only way I can think to do this is something like this:
[tt]
my %l2;
$l2{sc1} = ${%$lineref}{sc1};
$l2{sc2} = ${%$lineref}{sc2};
$l2{sc3} = ${%$lineref}{sc3};
$l2{arr} = ${%$lineref}{arr};
[/tt]
followed by
[tt]
push(@newarray, \%l2)
[/tt]

However, that's where my problem lies. the scalars move into the new array right, but ${%$lineref}{arr} doesn't. I also discovered that by that point, simply to access one of the values of that array, I have to dereference 3 times. For example, the first element at that point is:
${@{${%$lineref}{arr}}}[0]

Anyway, that might be irrelevant. My question is this. How do I transfer the array stored in ${%$lineref}{arr} to the new array, such that it can be accessed like this:

$newarray[idx]{arr}[0] through $newarray[idx]{arr}[n]

It really shouldn't be that complicated. I'm sure I'm just overlooking something.
Thanks
 
use the DATA::Dump module to check your data structure, it can be very helpful to track down problems:

Code:
use Data::Dump qw(dump);

#your code here

my $str = dump(@yourarray);
print $str;

just feed any of your data into the dump() function you wish to check.

 
To answer your question:
Through experimentation, it seems that shift returns a reference to the array element. right?
shift() returns what it removed from the array - so, if you remove a reference, it will return the reference. Or, if you remove a scalar, that's what you'll get out. I hope that helps!


Here's some code that may straighten out the problem you're having. I modified your split pattern for my own sanity. Also, using KevinADC's suggestion, I used Data::Dumper to print out the results.
Code:
use Data::Dumper;

my (@lines, @l2);

while (<DATA>) {
    my ($s1, $s2, $s3, @a) = split(/\s+/, $_);
    chomp ($s1, $s2, $s3, @a);
    push (@lines, {sc1 => $s1, sc2 => $s2, sc3 => $s3, arr => \@a});
}

#Makes a copy of the reference to the hash at $lines[1]
push @l2, \%{$lines[1]};

print Dumper(\@lines);
print Dumper(\@l2);

__DATA__
1   2   3   101   102   103
5   10  15  205   210   215
21  22  23  321   322   323
 
Occasionally I want to shift one of those array elements off. Through experimentation, it seems that shift returns a reference to the array element. right?

$lineref = shift(@lines);

$lineref now contains a reference to an anonymous hash, which is what you are storing in the array. The shift statement removes elements from the beginning of an array and returns them; pop does the same thing from the end of the array.

now I want information added into a NEW array of hashes. The only way I can think to do this is something like this:

my %l2;
$l2{sc1} = ${%$lineref}{sc1};
$l2{sc2} = ${%$lineref}{sc2};
$l2{sc3} = ${%$lineref}{sc3};
$l2{arr} = ${%$lineref}{arr};

push(@newarray, \%l2)


The first danger here is that you're using a fixed hash in making the construct - you need to use an anonymous hash from the start or you run into reusability problems. Then you need to copy the array, not just the reference:

my $l2 = {};
$l2->{sc1} = $lineref->{sc1};
$l2->{sc2} = $lineref->{sc2};
$l2->{sc3} = $lineref->{sc3};
$l2->{arr} = [@{$lineref->{arr}}];

push(@newarray, $l2);
 
One final note. Neither the form
${@{${%$lineref}{arr}}}[0]
nor the form
$newarray[idx]{arr}[0]
are actually good ways to refer to this kind of referencing. They work - almost anything does in Perl, if you buy it flowers - but the most consistent format (and one Perl always understands correctly) is:
$lineref->{arr}->[0] and
$newarray[idx]->{arr}->[0]
This clearly marks where the references are to anonymous items and where not - by always prefixing an anonymous reference with -> the format remains consistent whether or not there is a static array or hash as part of the line.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top