If the fruits are sorted, two binary searches would find the fruits quickly.
sub search_cmp
my @fruits = (
{ name => "Orange", price => 40, ... },
...
);
my @ranges = (
[ 35, 55 ],
...
);
my @sorted_fruits = sort { $a->{price} <=> $b->{price} } @fruits;
for my $range (@ranges) {
my $i = binsearch { $a <=> $b->{price} } $range[0], @sorted_fruits, 0;
$i = ~$i if $i < 0;
my $j = binsearch { $a <=> $b->{price} } $range[1], @sorted_fruits, $i;
$j = ~$j - 1 if $j < 0;
say "[$range->{min}, $range->{max}]: @fruits[$i..$j]";
}
sub _unsigned_to_signed { unpack('j', pack('J', $_[0])) }
sub binsearch(&$\@;$$) {
my $compare = $_[0];
#my $value = $_[1];
my $array = $_[2];
my $min = $_[3] // 0;
my $max = $_[4] // $#$array;
return -1 if $max == -1;
my $ap = do { no strict 'refs'; \*{caller().'::a'} }; local *$ap;
my $bp = do { no strict 'refs'; \*{caller().'::b'} }; local *$bp;
*$ap = \($_[1]);
while ($min <= $max) {
my $mid = int(($min+$max)/2);
*$bp = \($array->[$mid]);
my $cmp = $compare->()
or return $mid;
if ($cmp < 0) {
$max = $mid - 1;
} else {
$min = $mid + 1;
}
}
return _unsigned_to_signed(~$min);
}
Performance analysis
The best possible worst case is O(R * F) because every range could match every fruit.
The naive approach described by the OP asked to replace is O(R * F). So is it as fast as it can be? No, because the naive approach always adopts its worse case.
In practice, if we can assume that each range matches just a few fruits, we can get far far better results on average from the above: O( ( F + R ) log F )