gatorreina
gatorreina

Reputation: 960

Difference between a direct perl hash reference and a hash that is turned into a reference

I am trying to understand an example of code given here: https://www.perlmonks.org/?node_id=1083257 and the difference between the directly created hash references given in the example and one that I alternatively create first as a hash. When I run the following code:

use strict;
use warnings;
use Algorithm::NaiveBayes;

my $positive = {
    remit => 2,
    due => 4,
    within => 1,
};
my $negative = {
    assigned => 3,
    secured => 1,
};

my $categorizer = Algorithm::NaiveBayes->new;
$categorizer->add_instance(
    attributes => $positive,
    label => 'positive');
$categorizer->add_instance(
    attributes => $negative,
    label => 'negative');

$categorizer->train;

my $sentence1 = {
    due => 2,
    remit => 1,
};

my $probability = $categorizer->predict(attributes => $sentence1);

print "Probability positive: $probability->{'positive'}\n";
print "Probability negative: $probability->{'negative'}\n";

I get the result:

Probability positive: 0.999500937781821
Probability negative: 0.0315891654410057

However, when I try to create the hash reference in the following way:

my %sentence1 = {
    "due", 2,
    "remit", 1
};

my $probability = $categorizer->predict(attributes => \%sentence1);

I get:

Reference found where even-sized list expected at simple_NaiveBayes.pl line 57.
Probability positive: 0.707106781186547
Probability negative: 0.707106781186547

Why is my hash \%sentence1 different from the $sentence1 hash reference given in the example?

Upvotes: 1

Views: 86

Answers (2)

TLP
TLP

Reputation: 67910

Just like the warning says, you are assigning a reference where an even-sized list was expected. This

my %sentence1 = {   # curly bracers create a hash reference, a scalar value
    "due", 2,
    "remit", 1
};

Should look like this

my %sentence1 = (   # parentheses used to return a list (*)
    "due", 2,
    "remit", 1
);

(*): Parentheses do not actually create a list, they just override precedence. In this case of = over , or =>, which returns a list of items to the assignment.

Or this

my $sentence1 = {    # scalar variable is fine for a reference
    "due", 2,
    "remit", 1
};

If you want to get technical, what is happening in your hash assignment is that the hash reference { ... } is stringified and turned into a hash key. (The string will be something like HASH(0x104a7d0)) The value of that hash key will be undef, because the "list" you assigned to the hash only contained 1 thing: The hash reference. (Hence the "even-sized list" warning) So if you print such a hash with Data::Dumper, you would get something that looks like this:

$VAR1 = {
          'HASH(0x104a7d0)' => undef
        };

Upvotes: 4

hobbs
hobbs

Reputation: 240521

my %sentence1 = {
    "due", 2,
    "remit", 1
};

You did this wrong (you tried to create a hash with one key, which is a hashref (which doesn't work) and no corresponding value). That's why perl gave you a warning about finding a reference instead of an even-sized list. You wanted

my %sentence1 = (
    "due", 2,
    "remit", 1
);

Upvotes: 4

Related Questions