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

hi there,

I have a hash map %result(). which has key,value pair. The key is $val(which has list of floating point values like 0.45458427 and value is $url which has list of urls

I use this hash map to print the url which the highest value in $val(i.e key).

my Question now is, when this $val has two or more values same i.e {value1:0.456234,val2:0.642323,val3:0.456234,val4:0.456234). what happens it prints the val4's url instead of val1's url. since val1,val3,val4 has the same score, I want it to go in order 1,2,3 like that. But it directly prints 4th.

What can be the suggestion..??
my %results = (); foreach my $result (@file_content) { my $tit = $1 if ($result =~ /<title>(.+?)<\/title>/i); next unless $tit; # skip, if tit is not available #print "\n$tit\n"; my $url = $1 if ($result =~ /<url>(.+?)<\/url>/i); my $val = jaccard($tit, $title); #print " $val\n"; $results{$val} = $url; } @results = sort {$b <=> $a} keys %results;#sorts in descending order. my $highest_val = $results[0];#takes the highest value print $highest_val; print "\n\n The Url Ur looking for is: $results{$highest_val}\n#print +s the url of highest values.
My code is this. i cant include the content of @file_content,because it very big. it has title,url,snippet for googles top 10 result. And "jaccard($tit,$title) is a funtion returns floating point value. since its also big i dint include. lets say $val has the following floating point values: 1-> 0.0588235294117647 2-> 0.0555555555555556 3-> 0.0588235294117647 4-> 0.0588235294117647 5-> 0 6-> 0.0555555555555556 7-> 0.0588235294117647 8-> 0.0555555555555556 here i expect the url of 2nd but getting url of 6th..

Replies are listed 'Best First'.
Re: hash map to give preference to 1st match
by bart (Canon) on Jun 23, 2011 at 11:14 UTC
    I think you're using the wrong data structure. Hashes cannot have duplicate keys, and floating point numbers are a bad match for hash keys, anyway. Like: "0.456234" and "0.4562340" is the same numerical value, yet it's a different string (and thus: hash key).

    I'd rather use an array of (value, url) tuples (maybe as anonymous arrays... With 2 loops, you can

    1. determine the max value
    2. fetch all tuples with that value.
    Actually, if you do it smarter (but more complex), you can do it in one loop.
    my @pairs = ([0.456234, 'url 1'], [0.42323, 'url 2'], [0.456234, 'url +3'], [0.456234, 'url 4']); my $max; my @url; foreach(@pairs) { if(!defined $max or $max < $_->[0]) { $max = $_->[0]; @url = $_->[1]; } elsif($max == $_->[0]) { # caution: exact identity with floati +ng point numbers is rare, so this might disappoint a little push @url, $_->[1]; } } use Data::Dumper; print Dumper (\@url);
    p.s. your original data is wrong, as it's the second value that is the highest. I modified that value in my test code.
Re: hash map to give preference to 1st match
by zentara (Archbishop) on Jun 23, 2011 at 11:00 UTC
    You probably want to sort the hash by fields first. Here's an example.
    #!/usr/bin/perl use strict; use warnings; #by davido of perlmonks # Name Sex Age IQ Hair Eyes my %hash = ( 'Lisa' => [ 'F', 6, 150, 'Blonde', 'Blue' ], 'Homer' => [ 'M', 40, 105, 'Bald', 'Blue' ], 'Bart' => [ 'M', 9, 120, 'Blonde', 'Brown' ], 'Marge' => [ 'F', 36, 135, 'Blue', 'Blue' ], 'Maggie' => [ 'F', 1, 130, 'Blonde', 'Blue' ] ); # Assume that @criteria is actually obtained at runtime. my @criteria = ( 0, 2, 3 ); my @comparisons; my ( $sample_key, $sample_value ) = each %hash; foreach ( @criteria ) { push @comparisons, "\$hash{\$a}[$_]" . ( $sample_value =~ /^\d+$/ ? " <=> " : " cmp " ) . " \$hash{\$b}[$_]"; } my $routine = join " || ", @comparisons; my @sorted; eval "\@sorted = sort { $routine } keys \%hash" or die "Ick!\n$@\n"; print $_, "\n" foreach @sorted;

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
      For this type of sort, rather than building up a code string and eval()ing, you might want to use Sort::MultipleFields.
Re: hash map to give preference to 1st match
by choroba (Cardinal) on Jun 23, 2011 at 10:50 UTC
    Using the name "value" for a key is confusing, try to change it to something else (float?).
    Hash variable cannot be used with round brackets (%result()).
    Are you sure you store the whole list of the URL's into your values (i.e. you use Hash of Arrays, HoA)? If yes, just use $result{$float}[0] to retrieve the first value. Do not you overwrite an older value with a new one when storing the values?
Re: hash map to give preference to 1st match
by DrHyde (Prior) on Jun 28, 2011 at 10:04 UTC

    You probably want to use a hash of arrayrefs:

    my %results; while(my($score, $url) = getnextpair()) { push @{$results{$score}}, $url; }

    Then to get the first URL that had a particular score ...

    my $url = $results{$score}->[0]

    and to get all the URLs that had a particular score ...

    my @urls = @{$results{$score}}

    And I'll echo what another monk said - please don't use $value or $val for the key in a hash, it's very confusing.