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

Hello,
I'm sure it's possible, but I don't know how, so I ask the wisdom of the monks.

Imagine I've got an array @a and I want use each value of the array as a key in a hash, like:

$b{$a[0]}, $b{$a[1]}, $b{$a[2]} ...
Is this possible without using a loop, just in one line? thanx :-D

Replies are listed 'Best First'.
Re: use array for hash-keys without loop
by almut (Canon) on Mar 11, 2010 at 12:15 UTC

    I think you want hash slices:

    #!/usr/bin/perl -l my @a = qw(foo bar baz); my %h; @h{@a} = (1, 42, 99); use Data::Dumper; print Dumper \%h; print "@h{@a}"; __END__ $VAR1 = { 'bar' => 42, 'baz' => 99, 'foo' => 1 }; 1 42 99
Re: use array for hash-keys without loop
by cdarke (Prior) on Mar 11, 2010 at 12:51 UTC
    my %hash; # Note: you cannot use 'my' on a slice @hash{@a} = (0) x @a; # Initialise values to zero @hash{@a} = undef; # No values @hash{@a} = @b; # Take values from @b
      $ perl -le' use Data::Dumper; my @a = "A" .. "D"; my %hash; $hash{@a} = (0) x @a; print Dumper \%hash; ' $VAR1 = { '4' => '0000' };

      Oops!

        $hash{@a} = (0) x @a;

        Using @hash{@a} (as cdarke did) instead of $hash{@a} avoids the issue...

Re: use array for hash-keys without loop
by toolic (Bishop) on Mar 11, 2010 at 15:04 UTC
Re: use array for hash-keys without loop
by ikegami (Patriarch) on Mar 11, 2010 at 15:57 UTC

    Impossible. You're asking to do something that's the very definition of looping without using a loop. What do you actually want?

    my $val = Dive(\%b, map \$_, @a); DiveVal(\%b, map \$_, @a)= $val;

    Check out Data::Diver.

    my $val = Dive(\%b, map \$_, @a); DiveVal(\%b, map \$_, @a) = $val;

    If @a contains no numbers, you can omit map \$_,.

    my $val = Dive(\%b, @a); DiveVal(\%b, @a) = $val;

    Update: I thought you had $b{$a[0], $a[1], $a[2]}. Using a slice is definitely the cleanest solution. You'd still be looping, though.

      You're asking to do something that's the very definition of looping without using a loop. What do you actually want?

      I also sometimes wonder why we regularly get questions how to do things "without a loop"...  but I think what people are typically looking for is just some kind of syntactic shortcut that avoids having to spell out things the cumbersome way. Like, for example in this case:

      my @a = qw(foo bar baz); my @b = (1, 42, 99); # unwanted (considered too clumsy): for my $i (0..$#a) { $h{$a[$i]} = $b[$i]; } # or $h{$a[0]} = 1; $h{$a[1]} = 42; $h{$a[2]} = 99; # or ($h{$a[0]}, $h{$a[1]}, $h{$a[2]}) = (1, 42, 99); # wanted: @h{@a} = @b; @h{@a} = (1, 42, 99);

      They don't particularly care about the internal implementation, i.e. that something behind the scenes of course will have to do the looping... At least, that's my guess.

        It's often about perceived performance, I believe.

        Sure, it's a clarity question here. What does that have to do with avoiding loops? I'd take

        $b{$_}=1 for @a;
        over
        @b{@a} = (1)x@a;

        even though the other might be considered to have no loop. (It has three while the first has two.)

        Actually, I'd take the following since it incorporates the my:

        my %b = map { $_ => 1 } @a;

      Impossible. You're asking to do something that's the very definition of looping without using a loop. What do you actually want?

      At university I learned that loops can be replaced by recursivity. So the simple code below fulfills the requirements of the OP (one line, no loop) ... but maybe isn't what he wants. ;-)

      However this statement stems from a course of theoretical computer science. Don't use the code below in a productive environment. It is slower and takes much more resources than the other, straightforward solutions presented in this thread!

      You have been warned! Rata

      use strict; use warnings; my @x = qw ( a b c d e ff ggg hhhh iiii ); my %y; # Tata!!! Here comes the requested line of code: noLoop(); sub noLoop { $y{pop(@x)} = 1; noLoop() if (scalar(@x)); } # + btw.: using global vars in subs is usually bad style ;-) print keys(%y), "\n"; exit 0;
        Yes, there's a lot of different ways of writing loops.

        Note that your code can be simplified to

        my %y; $y{shift(@x)} = 1 while @x;
        or the non-destructive
        my %y = map { $_ => 1 } @x;
Re: use array for hash-keys without loop
by Ratazong (Monsignor) on Mar 11, 2010 at 12:20 UTC
Re: use array for hash-keys without loop
by Anonymous Monk on Mar 11, 2010 at 21:14 UTC
    use List::MoreUtils qw/mesh/; my %b = mesh @a, @c;
Re: use array for hash-keys without loop
by Anonymous Monk on Mar 11, 2010 at 12:56 UTC
    Why don't you want to use a loop?
Re: use array for hash-keys without loop
by Anonymous Monk on Mar 11, 2010 at 16:17 UTC
    @a=qw(a b c d); @b{@a}=(1,2,3,4); foreach $key (keys %b) { print"$key => $b{$key}\n"; }