Why can't I access an Array like this?

B

Bill H

This has always vexed me. When trying to access an array in the
following manner it never works and I end up assigning a variable. Can
someone point me to some docs on what I am doing wrong?

Example to show the issue, not my real code:

for($i = 0;$i < 4;$i++)
{
$temp = substr("0000".$i,-4);
$in{'VALUE$i'} = $i; # This never works
}

The $in{'VALUE$i'} never works, I have tried a number of different
ways:

$in{"VALUE$i"}
$in{"VALUE".$i}
ect

The only thing that seems to work is:

$a = "VALUE$i";
$in{$a} = $i;

But this can be cumbersome when I have a lot of variables I am trying
to set. I am sure there is some simple perl way of doing this, I just
have never found it yet.

Bill H
 
J

Jürgen Exner

Bill said:
This has always vexed me. When trying to access an array in the
following manner it never works and I end up assigning a variable. Can
someone point me to some docs on what I am doing wrong?

Example to show the issue, not my real code:

for($i = 0;$i < 4;$i++)

for my $i (0..3)
{
$temp = substr("0000".$i,-4);
$in{'VALUE$i'} = $i; # This never works

There is no array here. Did you mean
$in['VALUE$i']
instead? 'VALUE$i' is the literal string without $i expanded. The numerical
value of that string would be 0. So that statement would be the same as
$in[0].
regardless of the value of $i.

jue
 
G

Gunnar Hjalmarsson

Bill said:
for($i = 0;$i < 4;$i++)
{
$temp = substr("0000".$i,-4);
$in{'VALUE$i'} = $i; # This never works
}

The $in{'VALUE$i'} never works,

Sure it does. It assigns to the hash key 'VALUE$i' - not expanded -
every time.
I have tried a number of different ways:

$in{"VALUE$i"}
$in{"VALUE".$i}

Please post a short but complete program to show us what problem you
have with those.
 
B

Bill H

Sure it does. It assigns to the hash key 'VALUE$i' - not expanded -
every time.



Please post a short but complete program to show us what problem you
have with those.

Here is a simple working example of what I am trying to do:

$in{'TEST0001'} = "Hello 0001";
$in{'TEST0002'} = "Hello 0002";
$in{'TEST0003'} = "Hello 0003";
$in{'TEST0004'} = "Hello 0004";


for($i = 1;$i < 5;$i++)
{
$a = substr("0000".$i,-4);
print "TEST$a = $in{'TEST$a'}\n";
}

for($i = 1;$i < 5;$i++)
{
$a = substr("0000".$i,-4);
$b = "TEST$a";
print "$b = $in{$b}\n";
}


The 1st for loop doesnt work as expected, but the second does.

Here is the output:

TEST0001 =
TEST0002 =
TEST0003 =
TEST0004 =
TEST0001 = Hello 0001
TEST0002 = Hello 0002
TEST0003 = Hello 0003
TEST0004 = Hello 0004


I am not sure why I need to go to the extra step of assigning a
variable (in this case $b) to access the data.

Bill H
 
X

xhoster

Bill H said:
Here is a simple working example of what I am trying to do:

$in{'TEST0001'} = "Hello 0001";
$in{'TEST0002'} = "Hello 0002";
$in{'TEST0003'} = "Hello 0003";
$in{'TEST0004'} = "Hello 0004";

for($i = 1;$i < 5;$i++)
{
$a = substr("0000".$i,-4);
print "TEST$a = $in{'TEST$a'}\n";
}

You are using non-interpolating quotes for the hash key, so not
surprisingly they don't interpolate. You need to use interpolating
quotes, and need ones that don't interfere with the outer quotes,
such as this:

print "TEST$a = $in{qq'TEST$a'}\n";

But once we are using qq construct, I'd prefer to change the character
that goes with it:

print "TEST$a = $in{qq{TEST$a}}\n";

Xho
 
R

Ron Bergin

Here is a simple working example of what I am trying to do:

$in{'TEST0001'} = "Hello 0001";
$in{'TEST0002'} = "Hello 0002";
$in{'TEST0003'} = "Hello 0003";
$in{'TEST0004'} = "Hello 0004";

for($i = 1;$i < 5;$i++)
{
$a = substr("0000".$i,-4);
print "TEST$a = $in{'TEST$a'}\n";

}
Due to the single quotes, you won't get the needed variable
interpolation.
for($i = 1;$i < 5;$i++)
{
$a = substr("0000".$i,-4);
$b = "TEST$a";
print "$b = $in{$b}\n";

}

The 1st for loop doesnt work as expected, but the second does.

Here is the output:

TEST0001 =
TEST0002 =
TEST0003 =
TEST0004 =
TEST0001 = Hello 0001
TEST0002 = Hello 0002
TEST0003 = Hello 0003
TEST0004 = Hello 0004

I am not sure why I need to go to the extra step of assigning a
variable (in this case $b) to access the data.
You wouldn't need to if you used proper quoting.

for($i = 1;$i < 5;$i++)
{
$a = substr("0000".$i,-4);
print qq(TEST$a = $in{"TEST$a"}\n);
}

My preference would be to write it like this:

for my $i (1..4) {
my $key = sprintf("TEST%0.4d", $i);
print "$key = $in{$key}\n";
}
 
R

Ron Bergin

Here is a simple working example of what I am trying to do:

$in{'TEST0001'} = "Hello 0001";
$in{'TEST0002'} = "Hello 0002";
$in{'TEST0003'} = "Hello 0003";
$in{'TEST0004'} = "Hello 0004";

for($i = 1;$i < 5;$i++)
{
$a = substr("0000".$i,-4);
$b = "TEST$a";
print "$b = $in{$b}\n";

}
Since you're working with a hash, why not simply iterate over it with
"each"?

foreach my $key ( sort keys %in ) {
print "$key = $in{$key}\n";
}
 
B

Bill H

You are using non-interpolating quotes for the hash key, so not
surprisingly they don't interpolate. You need to use interpolating
quotes, and need ones that don't interfere with the outer quotes,
such as this:

print "TEST$a = $in{qq'TEST$a'}\n";

But once we are using qq construct, I'd prefer to change the character
that goes with it:

print "TEST$a = $in{qq{TEST$a}}\n";

Xho

--
--------------------http://NewsReader.Com/--------------------
Usenet Newsgroup Service $9.95/Month 30GB- Hide quoted text -

- Show quoted text -

Xho,

I knew there was some way of doing it Thanks for pointing out using
the qq construct!

Ron,

I use the keys hash alot, but for this usage I needed to do it
differently. Basically what the processor is doing is reading in form
values and all I know about the form values is that there are 10
fields that start with different words and end in ???? where ???? is
0001 - 9999. I also know how many groups of these values there are so
I have to do a for loop to read in the values for each group based on
the starting word and a counter, checking that some of the groups
aren't empty etc.

Bill H
 
J

Jürgen Exner

Bill said:
Here is a simple working example of what I am trying to do:

$in{'TEST0001'} = "Hello 0001";
$in{'TEST0002'} = "Hello 0002";
$in{'TEST0003'} = "Hello 0003";
$in{'TEST0004'} = "Hello 0004";

As I mentioned in an earlier reply you don't have arrays. Those are hashes.
for($i = 1;$i < 5;$i++)

Better written as
for my $i (1..4)
{
$a = substr("0000".$i,-4);
print "TEST$a = $in{'TEST$a'}\n";

I you had used strict and warnings this would have generated
Use of uninitialized value in concatenation (.) or string at ...
As others have pointed out using single quotes doesn't interpolate the
variable, so you were looking for the literal key 'TEST$a' which doesn't
exist, of course.

It appears that
print "TEST$a =" . $in{"TEST$a"} . "\n";
will do what you seem to be looking for.

But looping through a hash is much easier done with
for (keys %in) {
print "$in{$_}\n";
}

Also using consecutively numbered variables (or hash keys in this case)
usually is a strong indicator that you are using the wrong data structure. A
hash of array would probably be a better choice.

jue
 
J

Jürgen Exner

Bill said:
I use the keys hash alot, but for this usage I needed to do it
differently. Basically what the processor is doing is reading in form
values and all I know about the form values is that there are 10
fields that start with different words and end in ???? where ???? is
0001 - 9999.

Are you talking about HTML/HTTP/Web forms by any chance? You are using the
CGI module, aren't you?
I also know how many groups of these values there are so
I have to do a for loop to read in the values for each group based on
the starting word and a counter, checking that some of the groups
aren't empty etc.

If yes, then @names = $query->param will return all the parameter names and
you can then use $value = $query->param('foo') to get
each individual value. No need to awkwardly read in your own copies.

jue
 
M

Michele Dondi

$in{'TEST0001'} = "Hello 0001";
$in{'TEST0002'} = "Hello 0002";
$in{'TEST0003'} = "Hello 0003";
$in{'TEST0004'} = "Hello 0004";


for($i = 1;$i < 5;$i++)
{
$a = substr("0000".$i,-4);

Why this substr() madness? What's wrong with sprintf()?
print "TEST$a = $in{'TEST$a'}\n";
}

for($i = 1;$i < 5;$i++)
{
$a = substr("0000".$i,-4);
$b = "TEST$a";
print "$b = $in{$b}\n";
}

How 'bout

$in{"$TEST$_"} = "$Hello $_" for '0001'..'0004'; # ?


Michele
 
M

Michele Dondi

Since you're working with a hash, why not simply iterate over it with
"each"?

foreach my $key ( sort keys %in ) {
print "$key = $in{$key}\n";
}

Just a minor nitpick: you're *not* "iterating over it with C<each>",
but iterating overt its *keys* with C<foreach>.


Michele
 
R

Ron Bergin

Since you're working with a hash, why not simply iterate over it with
"each"?
foreach my $key ( sort keys %in ) {
print "$key = $in{$key}\n";
}

Just a minor nitpick: you're *not* "iterating over it with C<each>",
but iterating overt its *keys* with C<foreach>.

Michele
--
{$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
(($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
.'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,

Ya, I changed my thought pattern while I was writing. I guess I
should proof read before hitting the send key.
 
R

Ron Bergin

Xho,

I knew there was some way of doing it Thanks for pointing out using
the qq construct!

Ron,

I use the keys hash alot, but for this usage I needed to do it
differently. Basically what the processor is doing is reading in form
values and all I know about the form values is that there are 10
fields that start with different words and end in ???? where ???? is
0001 - 9999. I also know how many groups of these values there are so
I have to do a for loop to read in the values for each group based on
the starting word and a counter, checking that some of the groups
aren't empty etc.

Bill H

The substr approach isn't going to work as expected when you have
varying amounts of leading zeros. I can't say for sure without seeing
your actual data, but you'd either want to use the sprintf approach
like I've shown, or use a regex to capture the digits.

Something like this:

foreach my $key ( sort keys %in ) {
if ( $key =~ /\D(\d{4})$/ ) {
print "$key = $in{$key}\n";
}
}
 
A

A. Sinan Unur

Why this substr() madness? What's wrong with sprintf()?

Maybe he wants to be able to make it to the front page of the Daily WTF.

(I know, it is "Worse than Failure" now, but I prefer the former name).
How 'bout

$in{"$TEST$_"} = "$Hello $_" for '0001'..'0004'; # ?

There is a philosophical issue here. Assuming he is implementing a
sparse data structure using hashes (and that's why he is not using
arrays despite the fact that his keys are integers), a simple name
change would make all the interpolation completely and utterly
unnecessary as well as making *ALL* of his code much more readable:

my %test;
$test{ $_ } = "Hello $_" for '0001' .. '0004';

print "$test{0003}\n";


Sinan
 
P

Peter J. Holzer

for($i = 1;$i < 5;$i++)
{
$a = substr("0000".$i,-4);
print "TEST$a = $in{'TEST$a'}\n";
}

for($i = 1;$i < 5;$i++)
{
$a = substr("0000".$i,-4);
$b = "TEST$a";
print "$b = $in{$b}\n";
}


The 1st for loop doesnt work as expected, but the second does. [...]
I am not sure why I need to go to the extra step of assigning a
variable (in this case $b) to access the data.

You don't. There is another difference between your two loops. Look more
closely.

hp
 
M

Michele Dondi

^
^

Ya, I changed my thought pattern while I was writing. I guess I
should proof read before hitting the send key.

/me too. Except that I do. But I still fail! ;-)
(For what can I smile on a day like this...</sidenote>)


Michele
 
M

Michele Dondi

Maybe he wants to be able to make it to the front page of the Daily WTF.

(I know, it is "Worse than Failure" now, but I prefer the former name).

I didn't know it had changed.
There is a philosophical issue here. Assuming he is implementing a
sparse data structure using hashes (and that's why he is not using
arrays despite the fact that his keys are integers), a simple name
change would make all the interpolation completely and utterly
unnecessary as well as making *ALL* of his code much more readable:

my %test;
$test{ $_ } = "Hello $_" for '0001' .. '0004';

print "$test{0003}\n";

Indeed!


Michele
 
B

Bill H

Maybe he wants to be able to make it to the front page of the Daily WTF.

(I know, it is "Worse than Failure" now, but I prefer the former name).




There is a philosophical issue here. Assuming he is implementing a
sparse data structure using hashes (and that's why he is not using
arrays despite the fact that his keys are integers), a simple name
change would make all the interpolation completely and utterly
unnecessary as well as making *ALL* of his code much more readable:

my %test;
$test{ $_ } = "Hello $_" for '0001' .. '0004';

print "$test{0003}\n";

Sinan

Sinan

It never occured to me to use sprintf, substr has always worked for
me, but now that you mention it I may just start using it.

As for the reason I wanted to use it the way I posted is that I have a
web form that starts out with
fields:

SNAME0001, SPASS0001, FRONT0001, BACK0001, TITLE0001, COPY0001,
TOC0001, FOR0001, ACK0001, CHAP0001 and the person using the form can
add / remove groups of fields (these 10 fields all ending with the
same numbers). I add and remove the fields dynamically in the perl
script to the web page, so I only know the starting letters of the
field (ie SNAME, SPASS, FRONT etc) and how many groups are on the
page. So I have to work my way through the groups of fields using a
for loop (hence the need for the 0001 - ????) to build the page.

Bill H
 
M

Michele Dondi

It never occured to me to use sprintf, substr has always worked for
me, but now that you mention it I may just start using it.

It's just a matter of not reinventing a wheel. (Possibly risking to do
so in a wrong way.) Similarly you could do:

my @odd;
for (my $i=0; $i<=10; $i++) {
push @odd, $i if $i%2;
}

But you may more easily do

my @odd = grep $_%2, 0..10;


Michele
 

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,754
Messages
2,569,528
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top