hard references/arrays

T

Tintin

I'm wanting to set up a loop of array names like:

#!/usr/bin/perl
use strict;
use diagnostics;

my (@name1, @name2, @name3);

foreach my $array qw(name1 name2 name3) {
foreach my $row (@$array) {
print "$row\n";
}
}

This doesn't compile of course and outputs:

Can't use string ("name1") as an ARRAY ref while "strict refs" in use at
/tmp/p
line 7 (#1)
(F) Only hard references are allowed by "strict refs". Symbolic
references are disallowed. See perlref.

So I looked up hard references in perlref, but couldn't see how it applied
to my problem.

Am I on the right track with the construct?
 
A

Anno Siegel

Tintin said:
I'm wanting to set up a loop of array names like:

#!/usr/bin/perl
use strict;
use diagnostics;

my (@name1, @name2, @name3);

foreach my $array qw(name1 name2 name3) {
foreach my $row (@$array) {
print "$row\n";
}
}

You want

foreach my $array ( \ @name1, \ @name2, \ @name3 ) {

....or

foreach my $array ( \ ( @name1, @name2, @name3) ) {

Anno
 
B

Brian McCauley

Anno said:
You want

foreach my $array ( \ @name1, \ @name2, \ @name3 ) {

Surely it's far more likey the OP really wants a single array of arrays.

perldoc perllol
 
P

Paul Lalli

Tintin said:
I'm wanting to set up a loop of array names like:

No you don't. First read
perldoc -q "variable name"
and then search Google for the absurdly large number of posts dealing
with "variable as a variable name" and "symrefs", including more than a
few in the last week.
#!/usr/bin/perl
use strict;
use diagnostics;

my (@name1, @name2, @name3);

foreach my $array qw(name1 name2 name3) {

Why would you want to loop through the *names* of the arrays instead of
the arrays themselves?
foreach my $row (@$array) {
print "$row\n";
}
}

This doesn't compile of course and outputs:

Can't use string ("name1") as an ARRAY ref while "strict refs" in use at
/tmp/p
line 7 (#1)
(F) Only hard references are allowed by "strict refs". Symbolic
references are disallowed. See perlref.

So I looked up hard references in perlref, but couldn't see how it applied
to my problem.

Because you've ill-defined your problem. This is basically an XY issue.
You have issue X, which is that you want to access each array one at a
time. You've decided the solution to that is Y, to loop through the
names of the arrays. Your method for Y doesn't work, so you're trying
to figure out a different way of doing Y, instead of figuring out the
proper way of doing X.
Am I on the right track with the construct?

No.

In the general case, loop through the arrays themselves instead of the
array names:
foreach my $arr (\@array1, \@array2, \@array3) {
foreach my $row (@$arr) {
print "$row\n";
}
}

HOWEVER, in this case all you're doing is printing each element of each
array, followed by a newline. Why even bother looping?

{
local $, = "\n";
print @array1, @array2, @array3;
}
print "\n";

Paul Lalli
 
B

Ben Morrow

Quoth "Paul Lalli said:
HOWEVER, in this case all you're doing is printing each element of each
array, followed by a newline. Why even bother looping?

{
local $, = "\n";
print @array1, @array2, @array3;
}
print "\n";

Come now :)

{
local ($,, $\) = ("\n", "\n");
print @array1, @array2, @array3;
}

Ben
 
P

Paul Lalli

Ben said:
{
local ($,, $\) = ("\n", "\n");
print @array1, @array2, @array3;
}

I was waivering between those two and:

{
local $" = "\n";
print "@array1\n@array2\n@array3\n";
}

The one you mentioned is probably best. :)

Paul Lalli
 
T

Tintin

Paul Lalli said:
No you don't. First read
perldoc -q "variable name"
and then search Google for the absurdly large number of posts dealing
with "variable as a variable name" and "symrefs", including more than a
few in the last week.

Yes, I am painfully aware of the gazillion questions along those lines.
Notice I said "like", meaning, what is the correct way of doing this.
Why would you want to loop through the *names* of the arrays instead of
the arrays themselves?

Because I wanted to use the array name along with its data.
Because you've ill-defined your problem. This is basically an XY issue.
You have issue X, which is that you want to access each array one at a
time. You've decided the solution to that is Y, to loop through the
names of the arrays. Your method for Y doesn't work, so you're trying
to figure out a different way of doing Y, instead of figuring out the
proper way of doing X.

Quite likely true (see below).

In the general case, loop through the arrays themselves instead of the
array names:
foreach my $arr (\@array1, \@array2, \@array3) {
foreach my $row (@$arr) {
print "$row\n";
}
}

OK, that shows me how to use hard references correctly. Thank you.
HOWEVER, in this case all you're doing is printing each element of each
array, followed by a newline. Why even bother looping?

{
local $, = "\n";
print @array1, @array2, @array3;
}
print "\n";

Now that's a useful piece of code, however let me wind the clock right back
and explain what I'm trying to do, ie: X.

I'm reading in a fields from a text file to be loaded into a database.
There are various sets of data that can have 1-6 lines of information. For
example

Address1=1 fred st
Address2=suburb
Address3=city

In the database, there are 6 columns defined for the Address, so what I need
to do is read in the addresses (and ensure that I account for records with
less than 6 lines). Now there are at least 6 other data types like this.

What I'm currently doing is

foreach my $i (0..5) {
push @insert_record,$addresses[$i];
}

foreach my $i (0..5) {
push @insert_record,$elements[$i];
}

and so on, to build up an array used to insert a record into the database.

Using repeated code like that is a red warning sign saying that it can be
compacted, however I wasn't (still aren't) sure of the best way of handling
it.

Note that the loop is needed to pad out the insert_record array with undef
values if the array being referenced is less than 6 elements. This ensures
that the fields match those defined in the database.

Hopefully that explains things a little better.
 
B

Brian McCauley

Tintin said:
Yes, I am painfully aware of the gazillion questions along those lines.

So, presumably, you should be painfully aware of the gazillion answers
saying "if you think you want a symref you probably really want a hash
of references instead".
Notice I said "like", meaning, what is the correct way of doing this.

Er, use a hash of references instead.
Because I wanted to use the array name along with its data.

In that case you probaly want a hash of array references instead.

[...] let me wind the clock right back
and explain what I'm trying to do, ie: X.

I'm reading in a fields from a text file to be loaded into a database.
There are various sets of data that can have 1-6 lines of information. For
example

Address1=1 fred st
Address2=suburb
Address3=city

In the database, there are 6 columns defined for the Address, so what I need
to do is read in the addresses (and ensure that I account for records with
less than 6 lines). Now there are at least 6 other data types like this.

What I'm currently doing is

foreach my $i (0..5) {
push @insert_record,$addresses[$i];
}

foreach my $i (0..5) {
push @insert_record,$elements[$i];
}

and so on, to build up an array used to insert a record into the database.

Using repeated code like that is a red warning sign saying that it can be
compacted,

however I wasn't (still aren't) sure of the best way of handling
it.

Like has been said in the gazillion threads alluded to above, use a hash
of references instead.

Replace the separate variables @addresses and @elements with a single
hash of arrays (say, %record) so @addresses becomes @{$record{ADDRESS}}
and @elements becomes @{$record{ELEMENT}}.
Note that the loop is needed to pad out the insert_record array with undef
values if the array being referenced is less than 6 elements.

No it isn't, a slice will do that perfectly well.

push @insert_record => map { @$_[0..5] } @record{'ADDRESS','ELEMENT'};
 
B

Brian McCauley

Tintin said:
Because I wanted to use the array name along with its data.
[...] let me wind the clock right back
and explain what I'm trying to do, ie: X.

[snip a lot of stuff that does not include any operations that use the
array name along with its data ]
Hopefully that explains things a little better.

No, it does not.
 
T

Tintin

Replace the separate variables @addresses and @elements with a single hash
of arrays (say, %record) so @addresses becomes @{$record{ADDRESS}} and
@elements becomes @{$record{ELEMENT}}.
Note that the loop is needed to pad out the insert_record array with
undef values if the array being referenced is less than 6 elements.

No it isn't, a slice will do that perfectly well.

push @insert_record => map { @$_[0..5] } @record{'ADDRESS','ELEMENT'};


Ahh, exactly what I need. Thanks for helping out.

BTW, needs to be

push @insert_record => map { @{$_}[0..5] } @record{'ADDRESS','ELEMENT'};
 
B

Brian McCauley

Tintin said:
push @insert_record => map { @$_[0..5] } @record{'ADDRESS','ELEMENT'};

needs to be

push @insert_record => map { @{$_}[0..5] } @record{'ADDRESS','ELEMENT'};

Not from perl's perspective it doesn't (for details 'perldoc perlref').

I grant you that some _people_ may find it more readable with the
redundant { }.
 
T

Tintin

Brian McCauley said:
Tintin said:
push @insert_record => map { @$_[0..5] } @record{'ADDRESS','ELEMENT'};

needs to be

push @insert_record => map { @{$_}[0..5] } @record{'ADDRESS','ELEMENT'};

Not from perl's perspective it doesn't (for details 'perldoc perlref').

Hmm. On the Perl version I was using (5.8.3 I think), I'm pretty certain it
made a difference. However, I've just tested with 5.8.0 and you are
correct, it makes no difference.

I'll have to double check the results on the platform I had the production
code on.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top