Perl newbie q: trying to access array using variable name

M

m

i checked the archives, but couldn't find anything that made sense to
me (blush). this is a generalized example of my problem:

i have a set of 100 lists:

@list1 = ...
@list2 = ...
@list3 = ...
@list4 = ...
@list5 = ...
....
@list 99 = ...
@list100 = ...

i want to then check a value to see what list it's in. instead of
writing 100 of these:

foreach $list1 (@list1) {
if $value =~ /$list1/ {
print "found the value in list1\n";
}
}

i want to put that in a loop that runs 100 times. in my mind, it
seems like i will be calling a list by a variable name that increments

$listTrigger = "list"
$counter = 1;
$listTrigger .= $counter;

until ( !exists @$listTrigger) {
if $value =~ /$list1/ {
print "found the value in $listTrigger\n";
}
++$counter;
}

i receive the following message: Can't use string ("list1") as an
ARRAY ref while "strict refs". any help would make me the happiest
boy on the planet.

matt
 
P

Paul Lalli

i checked the archives, but couldn't find anything that made sense to
me (blush). this is a generalized example of my problem:

i have a set of 100 lists:

@list1 = ...
@list2 = ...
@list3 = ...
@list4 = ...
@list5 = ...
...
@list 99 = ...
@list100 = ...

i want to then check a value to see what list it's in. instead of
writing 100 of these:

foreach $list1 (@list1) {
if $value =~ /$list1/ {
print "found the value in list1\n";
}
}

i want to put that in a loop that runs 100 times. in my mind, it
seems like i will be calling a list by a variable name that increments

$listTrigger = "list"
$counter = 1;
$listTrigger .= $counter;

until ( !exists @$listTrigger) {
^^^^^^^^^
"until not"? Ew. Why not just use 'while'? But I digress...
if $value =~ /$list1/ {
print "found the value in $listTrigger\n";
}
++$counter;
}

i receive the following message: Can't use string ("list1") as an
ARRAY ref while "strict refs". any help would make me the happiest
boy on the planet.

What you are trying to do is use what are known as "soft references".
That is, use a variable containing a string as the name of a different
variable. This is generally considered A Very Bad Idea, which is why it
is disallowed under 'use strict'.

Now, the cheesy way out of your predicament might just be to get rid of
strict refs while in that block:

{
no strict 'refs';
$listTrigger = "list1";
while (exists @$listTrigger){ ... }
}

But this is another Bad Idea. (Indeed, I'll probably be yelled at by
members of this group for even suggesting it). Instead, what you should
be doing is redesigning your program just slightly. Rather than having
100 distinct arrays, why not have one array containing 100 array
references:

my @big_array = (
[1, 2, 3, 4],
['foo', 'bar','baz'],
#etc
);

Now you can just have a double loop to go through everything:

for (my $i=0; $i < @big_array; $i++){
foreach $list_item (@{$big_array[$i]}){
if ($value =~ /$list_item/){
print "Found it in array $i\n";
}
}
}

(Note that I've used your logic from above, which is testing to see if
some unknown value contains as a substring the list item that's currently
being examined. This may or may not be what you actually want.

I hope this was clear enough to get you pointed in the right direction.
If you've never used multi-dimensional arrays, you might want to look over
the following documentation:
perldoc perlreftut
perldoc perldsc
perldoc perllol

Paul Lalli
 
J

Juha Laiho

(e-mail address removed) (m) said:
i checked the archives, but couldn't find anything that made sense to
me (blush). this is a generalized example of my problem:

i have a set of 100 lists:

@list1 = ...
@list2 = ...
@list3 = ...
@list4 = ...
@list5 = ...
...
@list 99 = ...
@list100 = ...

And there you have a design problem that calls for multi-dimensional
arrays, aka arrays of arrays (AoA in short, or LoL -- lists of lists).
See "perldoc perllol".
i want to then check a value to see what list it's in. instead of
writing 100 of these:

foreach $list1 (@list1) {
if $value =~ /$list1/ {
print "found the value in list1\n";
}
}

.... and this makes me wonder should the inner elements in the structure
actually be hashes instead of arrays. Hashes are indexed by name, so
you could store your values directly as hash keys, and this checking
for existence would become much easier (your proposed =~ doesn't work
for list contents; with hashes you could use a test like
"if exists $list{$value}".

Perhaps if you could describe a higher-level view of what it is you're
building, we could give you even better directions on how to achieve that.
 
T

Tore Aursand

i checked the archives, but couldn't find anything that made sense to
me (blush). this is a generalized example of my problem:

i have a set of 100 lists:

@list1 = ...
@list2 = ...
@list3 = ...
@list4 = ...
@list5 = ...
...
@list 99 = ...
@list100 = ...

What you really _want_ is an array of arrays. You _really_ don't want to
deal with a static number of lists (as above) when you don't have to.
i want to then check a value to see what list it's in. instead of
writing 100 of these:

foreach $list1 (@list1) {
if $value =~ /$list1/ {
print "found the value in list1\n";
}
}

Are you sure you want a regular expression like the one above? The one
above will only match if '$value' contains the value of '$list1'. Are you
sure you don't want it the other way around, ie. to check if '$list1'
contains '$value'?

If you had an array of arrays, you could do it like this;

my @lists = ( ... ); # An array which contains your sub-lists
my $value = ...; # The value you are searching for

for ( my $i = 0; $i <= $#lists; $i++ ) {
foreach ( @{$lists[$i]} ) {
if ( /$value/ ) {
print "'$value' found in list #" . $i . "\n";
}
}
}

If you don't care about what list there is a match, you could replace the
outer 'for()' loop with a 'foreach ()' loop and drop the '$i' variable.

You could also enhance the code above by using 'grep' where it is
appropriate.
 
J

John Bokma

Tore said:
i checked the archives, but couldn't find anything that made sense to
me (blush). this is a generalized example of my problem:

i have a set of 100 lists:

@list1 = ...
@list2 = ...
@list3 = ...
@list4 = ...
@list5 = ...
...
@list 99 = ...
@list100 = ...


What you really _want_ is an array of arrays. You _really_ don't want to
deal with a static number of lists (as above) when you don't have to.

i want to then check a value to see what list it's in. instead of
writing 100 of these:

foreach $list1 (@list1) {
if $value =~ /$list1/ {
print "found the value in list1\n";
}
}


Are you sure you want a regular expression like the one above? The one
above will only match if '$value' contains the value of '$list1'. Are you
sure you don't want it the other way around, ie. to check if '$list1'
contains '$value'?

If you had an array of arrays, you could do it like this;

my @lists = ( ... ); # An array which contains your sub-lists
my $value = ...; # The value you are searching for

for ( my $i = 0; $i <= $#lists; $i++ ) {
foreach ( @{$lists[$i]} ) {
if ( /$value/ ) {
print "'$value' found in list #" . $i . "\n";
}
}
}

If you don't care about what list there is a match, you could replace the
outer 'for()' loop with a 'foreach ()' loop and drop the '$i' variable.

You could also enhance the code above by using 'grep' where it is
appropriate.

Or when you need to do a lot of lookups, use hashes.
 
G

Gunnar Hjalmarsson

m said:
i have a set of 100 lists:

@list1 = ...
@list2 = ...
@list3 = ...
@list4 = ...
@list5 = ...
...
@list 99 = ...
@list100 = ...

Even if I don't know how you populate those lists, it appears to be an
inappropriate starting point. Instead of 100 arrays you should use an
array of arrays or a hash of arrays. This is an example of a hash of
arrays:

my %lists = (
1 => [ 1, 2, 3 ],
2 => [ 4, 5, 6 ],
3 => [ 7, 8, 9 ],
);
i want to then check a value to see what list it's in. instead of
writing 100 of these:

foreach $list1 (@list1) {
if $value =~ /$list1/ {
print "found the value in list1\n";
}
}

i want to put that in a loop that runs 100 times.

With a hash of arrays it can be done like this:

for my $list (keys %lists) {
for my $elem ( @{ $lists{$list} } ) {
if ($value =~ /$elem/) {
print "found the value $value in list $list\n";
}
}
}

HTH
 
D

David K. Wall

m said:
i have a set of 100 lists:

@list1 = ...
@list2 = ...
@list3 = ...
@list4 = ...
@list5 = ...
...
@list 99 = ...
@list100 = ...

As others have pointed out, all these lists are probably the wrong
approach.
i want to then check a value to see what list it's in. instead of
writing 100 of these:

Below is an idea you might be able to adapt. The list of lists (@LoL)
is hacked together just to get a demo working, so it's ugly and not
what I would really use (given a choice).

It would help if we knew more about the data. If we knew what the
data is, how it's read, and what you want to do with it we might
suggest something different.


use strict;
use warnings;

my @list0 = qw(j s t j o 2);
my @list1 = qw(a b d 2 h d s);
my @list2 = qw(d l w s v n 7 2 h);
my @list3 = qw(X w f h 4 j df c b);
my @list4 = qw(X g h j 4 f x m x);
my @list5 = qw(X t f j m 4 c);

# somehow the list of lists gets populated....
my @LoL = (\@list0, \@list1, \@list2, \@list3, \@list4, \@list5);

my %hash;
for my $list_number (0 .. $#LoL) {
for my $element ( @{$LoL[$list_number]} ) {
$hash{$element}{$list_number}++;
}
}

my $find = 'X';
print "$find exists in list(s) ",
join ', ', sort keys %{$hash{$find}};
 
T

Tad McClellan

m said:
i have a set of 100 lists:

@list1 = ...
@list2 = ...
@list3 = ...
@list4 = ...
@list5 = ...
...
@list 99 = ...
@list100 = ...


Then you have made a poor choice of data structure.

A 2-D array would have made it easy to solve your problem.

I'd redesign it to use a LoL if I were you.

$list[0] = [ stuff that used to be in @list1 ];
$list[1] = [ stuff that used to be in @list2 ];
...
$list[99] = [ stuff that used to be in @list100 ];

i want to then check a value to see what list it's in. instead of
writing 100 of these:

foreach $list1 (@list1) {
if $value =~ /$list1/ {


Errr, when did you put something into $value?

I think you have that backwards.

Don't you want $value in the pattern instead of being the string
that is searched?

print "found the value in list1\n";
}
}

i want to put that in a loop that runs 100 times.


# untested
foreach my $i ( 0 .. 99 ) {
foreach my $elem ( @{ $list[$i] } ) {
if ( $elem =~ /$value/ ) {
print "found the value in list[$i]\n";
}
}
}
 
M

m

yes... you are all very correct--this is not how i want to be doing
this :)

ever wish you could retract a post (you can't, can you?)?

a little digging later and a helpful phone call from an associate got
me on a more correct track. thanks for your notes--i will put them to
good use.

matt
 
E

Eric Schwartz

Tad McClellan said:

Which unfortunately doesn't help once it gets past google's servers
onto the vast majority of newsservers out there that DON'T honor
cancel requests. I'm not saying you're wrong, Tad, but I didn't want
the OP to think that canceling a post is likely to be effective
outside a very small subset of USENET.

-=Eric
 
A

Alan J. Flavell

Which unfortunately doesn't help once it gets past google's servers
onto the vast majority of newsservers out there that DON'T honor
cancel requests. I'm not saying you're wrong, Tad, but I didn't want
the OP to think that canceling a post is likely to be effective
outside a very small subset of USENET.

Yes, due to past abuses, cancels tend to be quite widely ignored.

My experience has been that Supersedes: is a much more effective way
to correct an erroneous posting on Usenet. (You have to remember how
to spell it, of course ;-) And I'm sorry to say that Google does not
seem to honour it, so the erroneous posting stays in their archive
along with its correction. But, quite widely respected by news
servers proper.
 

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,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top