dynamic access to multidimensional array

  • Thread starter Stefan Schnitter
  • Start date
S

Stefan Schnitter

Hi,

Is it somehow possible to index an array by another array?
Example:

@AoA = (
[ "fred", "barney" ],
[ "george", "jane", "elroy" ],
[ "homer", "marge", "bart" ],
);

and I have another array

@ind = ( 0, 1 );

How can I use @ind to index @AoA to get $AoA[0][1] ?
(and I *dont* want to write $AoA[$ind[0]][$ind[1]], since this might be dynamic:
@ind might have length 1,2,3,...)

Any ideas?

TIA,

Stefan
 
B

Brian McCauley

Is it somehow possible to index an array by another array?
Example:

@AoA = (
[ "fred", "barney" ],
[ "george", "jane", "elroy" ],
[ "homer", "marge", "bart" ],
);

and I have another array

@ind = ( 0, 1 );

How can I use @ind to index @AoA to get $AoA[0][1] ?

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

sub index_AoA : lvalue {
my $v = \shift;
$v = \$$v->[$_] for @{shift()};
$$v;
}

my @AoA = (
[ "fred", "barney" ],
[ "george", "jane", "elroy" ],
[ "homer", "marge", "bart" ],
);

my @ind = ( 0, 1 );

print index_AoA(\@AoA,\@ind),"\n";

index_AoA(\@AoA,[1,1]) = 'june';

print $AoA[1][1],"\n";

__END__

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
A

Anno Siegel

Stefan Schnitter said:
Hi,

Is it somehow possible to index an array by another array?
Example:

@AoA = (
[ "fred", "barney" ],
[ "george", "jane", "elroy" ],
[ "homer", "marge", "bart" ],
);

and I have another array

@ind = ( 0, 1 );

How can I use @ind to index @AoA to get $AoA[0][1] ?
(and I *dont* want to write $AoA[$ind[0]][$ind[1]], since this might be dynamic:
@ind might have length 1,2,3,...)

You'll need a recursive access routine for that. Here is one way to
write it:

sub nested_access {
my $array = shift;
my ( $i, @rest) = @_;
@rest ? nested_access( $array->[ $i], @rest) : $array->[ $i];
}

Called as

my $x = nested_access( \ @AoA, 0, 1);

it will set $x to "barney".

Anno
 
A

Anno Siegel

Abigail said:
Brian McCauley ([email protected]) wrote on MMMDCLXI September MCMXCIII in
<URL:`' (e-mail address removed) (Stefan Schnitter) writes:
`'
`' > Is it somehow possible to index an array by another array?
`' > Example:
`' >
`' > @AoA = (
`' > [ "fred", "barney" ],
`' > [ "george", "jane", "elroy" ],
`' > [ "homer", "marge", "bart" ],
`' > );
`' >
`' > and I have another array
`' >
`' > @ind = ( 0, 1 );
`' >
`' > How can I use @ind to index @AoA to get $AoA[0][1] ?

[snip of recursive solution]
Eck. Why so difficult? 'eval' makes it very easy:

#!/usr/bin/perl

use strict;
use warnings;

my @AoA = ([qw /fred barney/],
[qw /george jane elroy/],
[qw /homer marge bart/]);

my @ind = (0, 1);

my $elem = do {local $" = "]["; eval "\$AoA [@ind]"};
die $@ if $@;

print $elem, "\n";
__END__
barney

The usual security concerns apply if @AoA comes from outside the program.
I wonder what's more efficient, but not enough to benchmark.

That aside, the solution is cute, but it looks like cheating. From one
point of view, it isn't a solution at all. It doesn't solve the problem
of multi-level indexing but uses the solution built into the Perl interpreter.
Thus, it gives no insight into the problem.

Of course, if the task isn't to gain insight but to get it done, it's
code re-use at its finest.

Anno
 
B

Brian McCauley

Abigail said:
Brian McCauley ([email protected]) wrote on MMMDCLXI September MCMXCIII in
`' sub index_AoA : lvalue {
`' my $v = \shift;
`' $v = \$$v->[$_] for @{shift()};
`' $$v;
`' }
Eck. Why so difficult? 'eval' makes it very easy:

my $elem = do {local $" = "]["; eval "\$AoA [@ind]"};
die $@ if $@;

Thankyou! I'm planning to do a talk at YAPC::Europe::2004 about some
of the issues surrounding the good the bad and the ugly uses of
eval-string.

I needed some good non-trivial examples where a simple eval solution
exists to a problem and were it looks amazingly elegant at one level
but is actually aborrently ugly to an experienced programmer.

BTW: You should have put some smileys in there. Some people may have
actually thought you were serious. I trust you _were_ joking.

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
B

Brian McCauley

Abigail said:
my $elem = do {local $" = "]["; eval "\$AoA [@ind]"};

The usual security concerns apply if @AoA comes from outside the program.

Unless I'm missing something, you mean @ind, not @AoA.

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
N

nobull

Abigail said:
Brian McCauley ([email protected]) wrote on MMMDCLXI September MCMXCIII in
<URL:&&
&& > my $elem = do {local $" = "]["; eval "\$AoA [@ind]"};
&&
&& [...] looks amazingly elegant at one level
&& but is actually aborrently ugly to an experienced programmer.

I guess I'm not an experienced programmer then.

"When I was a child I spoke as a child I understood as a child I
thought as a child; but when I became a man I put away childish
things." I Cor. xiii. 11.

20 years ago I was a child and I was an inexperienced programmer (~5y)
and my language of choice was "Beeb BASIC"[1].

It happens that Beeb BASIC has an EVAL() function very similar to
Perl's eval().

It was also worth noting that the Beeb had only 7K of user RAM in it's
highest resolution/depth graphics modes so anything that saved a byte
was good.

I used to delight in things like this.

Now I program for a living.

Now I maintain code written by others.

Now I code libraries that are reused.

Now I code that others maintain.

Now I don't do things like that execpt under very special
circumstances (like scripts that I know are to be used once and thown
away).
&& I trust you _were_ joking.

I wasn't.

Oh dear.
Being able to do stuff like this is what makes Perl Perl.
Agreed.

I really hate dogma's like "you can't use string eval".

Me too.
Restricting
yourself to part of the language is something for the FWP mailinglist,
but a serious programmer should use the full power of the language.

Using the full power of the language does not mean that when there is
a choice of tools you use a technique just because you haven't used it
for while.
And the whining "but if @ind comes from the outside, it's dangerous"
gets old fast.

Using eval here is not ugly because it is insecure. It's very hard to
explain the real reason. Which is why people usually end up saying
"it's dangerous". But that's not the real reason.

It's not really a security problem since if you've got tainting on
@ind can't come from an external source unless it's been laundered, in
which case it's probably been laundered with /^(\d+)$/ so that's OK.

It is ugly because it blurs the code/data divide for no beniefit.

The eval approach is not really any shorter (if you reduce the refs
approach to it's minimum inlined form too), and the eval approach is
certainly slower.

timethese 100000 => {
eval => sub {
my $elem = do {
local $" = "][";
eval "\$AoA [@ind]";
};
},
refs => sub {
my $elem = \@AoA;
$elem = $elem->[$_] for @ind;
},
}

Benchmark: timing 100000 iterations of eval, refs...
eval: 6 wallclock secs ( 5.84 usr + 0.06 sys = 5.90 CPU)
@ 16949.15/s (n=100000)
refs: 1 wallclock secs ( 0.59 usr + 0.00 sys = 0.59 CPU)
@ 169491.53/s (n=100000)

Blurring the code/data line is a very powerfull tool and I think many
people are undely scared of using it when it is sensible to do so.
Indeed that is to be topic of my talk in Belfast.

But I don't think this is a case when it is sensible. One of my major
tasks over the next few months is to pin down exactly why I think
that.
'unlink $file' is dangerous if $foo comes from the outside
as well, but that's no reason to not use unlink. I'm fully aware that if
you run on behalve of some other user (suid, CGI, etc) there are issues -
issues that go much further than string eval. But the vast majority of
the programs I write runs under the same UID as the user invoking it. If
the user wants to screw himself, he doesn't need my programs to do so.

If you take a look at Message-ID: <[email protected]>
http://groups.google.com/[email protected]
and the thread containing it you will see that I'm usually on your
side of this argument.

[1] http://www.bbcbasic.com/
 

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

Forum statistics

Threads
474,257
Messages
2,571,031
Members
48,768
Latest member
first4landlord

Latest Threads

Top