vladb has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks,

I'm wondering if there's any good way to retreave values from an array in pairs. Here's what I got:
sub foo { while (@_) { my $var = shift; my $val = shift; print "var = $var; val = $val\n"; } } my @array = (a=>1, b=>2, c=>3); foo(@array);


This code certainly works, but I'd like to do away with the two shift() calls. My question really is, why wouldn't this work (reports an error):
my ($var, $val); for (($var, $val) = each %{@_}) { print "var = $var; val = $val\n"; }

The error I get says:
Bizarre copy of ARRAY in leave at arrays.pl line 14, <IN> chunk 5.

It doesn't really matter to me which way to go (about implementing this) but, what does that error mean? I might be missing something simple and evident ;-).

sorry for bugging ya for such little thing ;).

"There is no system but GNU, and Linux is one of its kernels." -- Confession of Faith

Replies are listed 'Best First'.
Re: Getting pair of values from an array
by japhy (Canon) on Dec 27, 2001 at 08:48 UTC
    Embrace splice():
    sub foo { while (my ($var, $val) = splice @_, 0, 2) { print "$var => $val\n"; } }

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker.
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: Getting pair of values from an array
by Aristotle (Chancellor) on Dec 27, 2001 at 13:58 UTC
    %{} tries to dereference a hash ref.. which @_ certainly isn't.
    my ($var, $val); for (($var, $val) = each %{{@_ }}) { print "var = $var; val = $val\n"; }
    Note the double brackets; the inner pair builds an anonymous hash and returns a reference to it which the outer pair with % dereferences. However, you have a big pitfall in there in that duplicate keys will lead to loss of data - so this is not a universally useful solution. As japhy said: use splice.
Re: Getting pair of values from an array
by innerfire (Novice) on Dec 27, 2001 at 10:34 UTC

    Your second example is on track: treat @_ as a hash.

    sub newfoo { my %hash = @_; foreach (keys %hash) {print "$_: $hash{$_}\n";} }

    When you use an array as a hash, it is automatically broken up into key, value pairs.

    http://www.nodewarrior.org/chris/

      ...treat @_ as a hash.

      You are not TREATING the array as a hash, but in fact COPYING its contents into one. As noted elsewhere by Screamer, using a hash ignores the potential data loss of duplicate keys in the data. splice() is the way to go.

      dmm

      You can give a man a fish and feed him for a day ...
      Or, you can
      teach him to fish and feed him for a lifetime
Re: Getting pair of values from an array
by rbc (Curate) on Dec 27, 2001 at 09:58 UTC
    Don't forget a recursive solution ...

    sub foo { my ($var, $val, @therest ) = @_; if ( !$val ) { return; } else { print "var = $var val = $val\n"; foo ( @therest ); } } my @array = (a=>1, b=>2, c=>3 ); foo (@array);

    --
    Its like a dog that can sing and dance.
    It's remarkable because it can do it.
    Not that it can do it well.
      Unless you're taking advantage of some tail-recursion optimization that I haven't heard about, recursion is probably a very bad idea for general-purpose iteration....

          -- Chip Salzenberg, Free-Floating Agent of Chaos

        Funny, I had mistaken the signature for a comment on the solution offered, and not a general signature.

        It does fit and address your point, does it not?

        (For the confused, the node under discussion is the grandparent of this node, not the parent.)

Re: Getting pair of values from an array
by robin (Chaplain) on Dec 27, 2001 at 18:39 UTC
    What version of Perl are you using? With 5.6.0 I get the error: Can't coerce array into hash which is certainly more informative...