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

This question is, quite honestly, entirely geared toward satisfying my curiosity.

Consider the following code.

my %hash; @hash{ qw/ one two three / } = ( 1 .. 3 ); foreach ( qw/ one one three two one / ) { print $hash{$_},"\n"; }

Now this is going to look wierd, and seem like a terribly ugly construction. But those caviets aside, why can this not be done by using an anonymous hash as follows:

foreach ( qw/ one one three two one / ) { print ${@{ qw/ one two three / } = (1..3)}{$_},"\n"; }

Is there no way for an unnamed hash to be asigned its keys and values using slices and lists, while referring to one of its values?

Dave

"If I had my life to do over again, I'd be a plumber." -- Albert Einstein

Replies are listed 'Best First'.
•Re: Defining an anonymous hash with slices and lists.
by merlyn (Sage) on Aug 27, 2003 at 21:33 UTC
      my %x is not anonymous
      I liked merlyn's example so much that I put it to work somewhere (because it can be done, not because this construct is clear or pretty).

      By the way, his answer reversed my original hash, but the idea was good, and its implication clear.

      To see it in action in a fully functional NATO Phonetic Alphabet Translator see this link. It's an impractical application, and this method isn't the "best way to do it", but it's an example of putting this method to work.

      Enjoy!

      Dave

      "If I had my life to do over again, I'd be a plumber." -- Albert Einstein

Re: Defining an anonymous hash with slices and lists. (It is possible!)
by BrowserUk (Patriarch) on Aug 27, 2003 at 23:07 UTC
    print ${+do{@{$_={}}{1..3}=qw[one two three];$_}}{2};

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
    If I understand your problem, I can solve it! Of course, the same can be said for you.

      Pity that I can only ++ it once ;-). Really neat piece of code.
      CombatSquirrel.
      Entropy is the tendency of everything going to hell.
Re: Defining an anonymous hash with slices and lists.
by PodMaster (Abbot) on Aug 27, 2003 at 22:07 UTC
    What's does a slice (assignment) return?
    warn @foo{1,2,3} = ( a .. c ); __END__ abc at - line 1.
    You can't do it with an unnamed hash for the same reason you can't do it with a named hash.

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.

      Thanks all, I've got it straight now. :) Never hurts to be inquisitive. PodMaster's explanation suddenly turned on the lightbulb.

      Dave

      "If I had my life to do over again, I'd be a plumber." -- Albert Einstein

Re: Defining an anonymous hash with slices and lists.
by chromatic (Archbishop) on Aug 27, 2003 at 21:40 UTC

    How is Perl to know that:

    @{ qw/ one two three / } = (1..3)

    is intended to be a hash declaration, not a list assignment?

      Well, actually the following does create a hash:

      my %hash; @hash{ qw/ one two three / } = ( 1..3 );

      And if you don't care about strictures, the  my %hash; part can even be eliminated.

      The problem comes when trying to pluck one of its values while defining it, like this:

      $someval = ${@hash{ qw/ one two three / } = ( 1..3 )}{two};

      And it only gets worse if you try to make it anonymous by removing the name "hash".

      Dave

      "If I had my life to do over again, I'd be a plumber." -- Albert Einstein

Re: Defining an anonymous hash with slices and lists.
by broquaint (Abbot) on Aug 28, 2003 at 09:27 UTC
    Or you could just not use a hash slice
    for( qw/ one one three two one / ) { print +{qw/ one 1 two 2 three 3 /}->{$_}, $/; } __output__ 1 1 3 2 1
    Or if you've got Language::Functional handy you could do this
    use Language::Functional 'zip'; for( qw/ one one three two one / ) { print +{@{zip([qw/one two three/],[1..3])}}->{$_}, $/; } __output__ 1 1 3 2 1
    Not quite as tidy as the first example, but it's closer to a hash slice.
    HTH

    _________
    broquaint

Re: Defining an anonymous hash with slices and lists.
by CombatSquirrel (Hermit) on Aug 27, 2003 at 23:35 UTC
    The following is quite ugly and either the keys or the values need to be typed in twice, but I just couldn't get closer to the solution (if there is one):
    #!perl use strict; use warnings; foreach my $val ( qw/ one one three two one / ) { print scalar { map { @{[(qw/one two three/, reverse (1..3))]}[$_ - 1, -$ +_] } (1..(2 * @{[1..3]})) }->{$val}, "\n"; }
    or just typed in once, but with one additional variable used within the outer map
    #!perl use strict; use warnings; foreach my $val ( qw/ one one three two one / ) { print scalar { map { my $intern = $_; map { @{$intern}[$_ - 1, -$_] } (1..@{$_}) } ([(qw/one two three/, reverse (1..3))]) }->{$val}, "\n"; }
    I could of course (ab)use an internal variable, but it remains another variable. Anyone have an idea?
    Cheers, CombatSquirrel.
    Entropy is the tendency of everything going to hell.
Re: Defining an anonymous hash with slices and lists.
by Aristotle (Chancellor) on Aug 28, 2003 at 11:19 UTC
    You're duplicating the qw/ one two three / in your own code. If you store this, you can obviate the need to store a hashref.
    my @keys = qw/ one two three /; foreach (@keys) { print ${{do{ local @_ = (@keys => 1 .. 3); map { $_[$_] => $_[$_+@keys] } 0 .. $#keys }}}{$_},"\n"; }

    Makeshifts last the longest.