Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

"Scalar found where operator expected", references

by jjohhn (Scribe)
on May 21, 2005 at 23:15 UTC ( #459286=perlquestion: print w/ replies, xml ) Need Help??
jjohhn has asked for the wisdom of the Perl Monks concerning the following question:

I am writing a subroutine that chooses a random key from a hash, but the choice is weighted depending on the value of the hash. The keys are a list of words from a text, the values are the frequency of occurence. (This is from the online book "Learning Perl the Hard Way" http://greenteapress.com/perl/)

anyway I don't understand the syntax error being flagged:

# sub weighted_hash # chooses and returns a random key from a hash; # the probability of choosing a specific key # is weighted by the value associated with that key sub weighted_hash{ my $hashref = shift; my %hash = $$hashref; my @weighted; foreach my $key (keys %hash){ my $weight = $hash{$key}; while ($weight >0){ push @weighted $key; $weight--; } } rand_elt @weighted; }
update: changed
push @weighted $hash{$key);
to
push @weighted $key;error still there

Comment on "Scalar found where operator expected", references
Select or Download Code
Re: "Scalar found where operator expected", references
by fglock (Vicar) on May 21, 2005 at 23:31 UTC

    You need a comma between the array and the scalar:

    push @weighted, $key;
Re: "Scalar found where operator expected", references
by sh1tn (Priest) on May 22, 2005 at 00:15 UTC
Re: "Scalar found where operator expected", references
by dave_the_m (Parson) on May 22, 2005 at 00:24 UTC
    In addition to the missing comma, the following line is nonsense:
    my %hash = $$hashref;
    You can either make a complete copy of the hash by doing
    my %hash = %$hashref;
    or more efficiently, just delete that line and always directly use the hashref, eg
    foreach my $key (keys %$hashref) { my $weight = $hashref->{$key}; ...

    Dave.

Re: "Scalar found where operator expected", references
by Roger (Parson) on May 22, 2005 at 09:21 UTC
    Other monks have already pointed out the bug and offered suggestions. I just want to show that there are more than one way to do it in Perl, depending on, personal taste, I'd say.

    # Implementation 1 - the mundane way sub weighted_hash { my $hashref = shift; my @weighted; for my $key (keys %$hashref) { for (1 .. $hashref->{$key}) { push @weighted, $key; } } rand_elt @weighted; } # Implementation 2 - the perl monk one-liner sub weighted_hash { my $hashref = shift; rand_elt map { my $key = $_; map { $key } 1 .. $hashref->{$key} } keys %$hashref; }


Re: "Scalar found where operator expected", references (perl6)
by mrborisguy (Hermit) on May 22, 2005 at 16:35 UTC

    Just thought I'd plug a few Perl6 ways of doing it, for future reference.

    my %hash = ( word => 1, second => 3, third => 7 ); ###### my @weighted = (); for %hash.keys -> $key { push @weighted, ( $key ) xx %hash{ $key }; } say @weighted.pick; ###### Basically the same thing: my @weighted = (); push @weighted, ( $_ ) xx %hash{ $_ } for %hash.keys; say @weighted.pick; ###### One-liner style. *Somewhat* based on Roger's above. %hash .keys .map:{ ( $_ ) xx %hash{ $_ } } .pick .say; ## (or actually on one line) %hash.keys.map:{ ( $_ ) xx %hash{ $_ } }.pick.say;

    (And if one of those Perl6 experts comes along, tell him or her that I'm still kinda new to p6, so there might even be better ways to do it! ;)

    -Bryan

Re: "Scalar found where operator expected", references
by TedPride (Priest) on May 22, 2005 at 16:45 UTC
    You need two passes, one to count the total number of words, the second to pick a word based on the rand value.
    use strict; use warnings; my (%h, %c); while (<DATA>) { chomp; @_ = split / /; $h{$_[0]} = $_[1]; } $c{weighted(\%h)}++ for 1..1000; print "$_ : $c{$_}\n" for sort {$c{$b} <=> $c{$a}} keys %c; sub weighted { my ($p, $c) = shift; $c += $_ for values %$p; $c = (int rand $c) + 1; for (keys %$p) { return $_ if ($c -= $p->{$_}) <= 0; } } __DATA__ gamma 7 beta 6 epsilon 3 alpha 2 delta 1

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://459286]
Approved by VSarkiss
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (8)
As of 2015-03-29 00:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When putting a smiley right before a closing parenthesis, do you:









    Results (628 votes), past polls