mj6174
mj6174

Reputation: 197

perl hash derived from array does not work as expected

I am having some trouble with using hash derived from array. It fails "exists" test for elements I know that are there. I wrote small test code to confirm this. Here it is:

#!/usr/local/bin/perl

my @sieve = (2, 3, 5, 7, 11, 13, 17, 19);
my %sieve_hash = @sieve;


foreach $prime (@sieve) {
    if (exists($sieve_hash{$prime})) {
    print "$prime exists!\n";
    } else {
    print "$prime DOES NOT exist.\n";
    }
}

Here is sample output:

2 exists!
3 DOES NOT exist.
5 exists!
7 DOES NOT exist.
11 exists!
13 DOES NOT exist.
17 exists!
19 DOES NOT exist.

What am I doing wrong?

Upvotes: 2

Views: 109

Answers (3)

ikegami
ikegami

Reputation: 386656

When assigning to a hash, a list of alternating keys and values are expected. The following would solve your problem:

my %sieve_hash = map { $_ => 1 } @sieve;

With the above, a simple truth test (rather than an existence test) would suffice. But since you're using an existence test, you could save some memory by using the following to assign undef instead of 1:

my %sieve_hash;
@sieve_hash{ @sieve } = ();

or

my %sieve_hash;
$sieve_hash{$_} = undef for @sieve;

I find a truth test much more elegant, though.

Upvotes: 8

OneSolitaryNoob
OneSolitaryNoob

Reputation: 5757

When you assign an array to a hash, the even indexed elements, e.g. $sieve[0], $sieve[2] become the hash keys, the odd numbered elements $sieve[1], $sieve[3], etc become the hash values. You'll notice the pattern in your output where only every other element (the 0th, 2nd, 4th) "exists" as a key in the hash.

Use Data::Dumper to see what's going on:

#!/usr/bin/perl

use Data::Dumper;

my @sieve = (2, 3, 5, 7, 11, 13, 17, 19);
my %sieve_hash = @sieve;

print STDERR "Your array:\n";
print Dumper \@sieve;

print STDERR "Your hash:\n";
print Dumper \%sieve_hash;



Your array:
$VAR1 = [
          2,
          3,
          5,
          7,
          11,
          13,
          17,
          19
        ];
Your hash:
$VAR1 = {
          '11' => 13,
          '17' => 19,
          '2' => 3,
          '5' => 7
        };

Upvotes: 1

Nate
Nate

Reputation: 1921

When you say

my %sieve_hash = @sieve;

It takes one every other element of the array as a key, the other elements as the value.

So your hash look the same as if it was constructed from:

my %sieve_hash = (
  2 => 3,
  5 => 7,
  ... and so on
);

Upvotes: 0

Related Questions