33

I have lines of code with two large arrays (so can't just write it into a hash) which I want to connect with a hash.

For example, $array1[0] becomes the key and $array2[0] becomes the value and so on to $array1[150],$array2[150].

Any ideas how I do this?

brian d foy
  • 129,424
  • 31
  • 207
  • 592
Jane
  • 383
  • 1
  • 4
  • 5

4 Answers4

69

You can do it in a single assignment:

my %hash;
@hash{@array1} = @array2;

It's a common idiom. From perldoc perldata on slices:

If you're confused about why you use an '@' there on a hash slice instead of a '%', think of it like this. The type of bracket (square or curly) governs whether it's an array or a hash being looked at. On the other hand, the leading symbol ('$' or '@') on the array or hash indicates whether you are getting back a singular value (a scalar) or a plural one (a list).

When I see one of these I see a mental image of a zipper...

cjm
  • 61,471
  • 9
  • 126
  • 175
martin clayton
  • 76,436
  • 32
  • 213
  • 198
  • 1
    Trivia: you're not the only one. In python there's a built-in function for converting two parallel arrays into a single array of two-element tuples, and it's called... zip()! http://docs.python.org/library/functions.html#zip :) – Simon Whitaker Sep 15 '10 at 08:57
  • 8
    Perl has a `zip` in [List::MoreUtils](http://search.cpan.org/dist/List-MoreUtils). There's also [Is there an elegant zip to interleave two lists in Perl ](http://stackoverflow.com/q/38345/8817). – brian d foy Sep 15 '10 at 11:11
17

martin clayton has the best answer for your general question, put there's also an interesting new feature in Perl 5.12. You can use each on an array so you can easily iterate through parallel arrays. It's useful when you want to manipulate the values before you use them:

 while( my( $index, $value ) = each @array1 ) {
      ...; # maybe do something to $value
      $hash{ $value } = $array2[$index];
      }
Community
  • 1
  • 1
brian d foy
  • 129,424
  • 31
  • 207
  • 592
4

(I tried posting this as a comment to brian's answer, but couldn't get the formatting right.)

You have to be careful to avoid nested uses of each. each works on a "global" iterator on the array. When it reaches the end, it returns false and then resets the position to the beginning. Thus following code results in an infinite loop.

Thanks to RJBS for his talk at YAPC::NA where he pointed out the global nature of the built-in iterator.

use strict;
use warnings;

my @array = 'A' .. 'J' ;

while ( my ($index, $value) = each @array){
        print "printing ($index, $value) from outer loop\n";

        while ( my ($index_in, $value_in) = each @array){
                print "printing ($index_in, $value_in) from inner loop\n";
        }
}
Christopher Bottoms
  • 11,218
  • 8
  • 50
  • 99
  • 1
    Well, you have to avoid all sorts of things that can mess up your program. This is all documented in the perlfunc entry for each. – brian d foy Sep 15 '10 at 15:34
  • @brian. I wasn't complaining about your answer, just wanting to help prevent hard-to-explain bugs. ;) In retrospect, I probably gave Too Much Information given the question at hand. – Christopher Bottoms Sep 15 '10 at 17:03
4
use List::MoreUtils qw( zip );

my @a = 'A' .. 'E';

my @b = 1 .. 5;

my %hash = zip @a, @b;
brian d foy
  • 129,424
  • 31
  • 207
  • 592
Felix
  • 41
  • 1