in reply to mapping lists

Here's a quick example showing your problem can be done using a binary search, even though the "25" is not in the list.

Note: my version returns only elements actually in the list. If you want all the integers in between, just return $F[$lo_pos]..$F[$hi_pos].

Update: It now appears that the index positions are wanted instead. No problem, that's just $lo_pos..$hi_pos.

use strict; use Search::Binary; my $lastIndex; sub reader { my ($handle, $val, $index) = @_; if (!defined $index) { $lastIndex++; } else { $lastIndex = $index; } return ($val <=> $handle->[$lastIndex], $lastIndex); } my @F = ( 1, 2, 4, 8, 16, 32..64 ); sub range{ my($lo, $hi) = @_; my $lo_pos = binary_search(0,$#F,$lo,\&reader,\@F); my $hi_pos = binary_search(0,$#F,$hi,\&reader,\@F); $hi_pos = $#F if ($hi_pos > $#F); return @F[$lo_pos..$hi_pos]; } print join(',', range(25,35)), "\n"; print join(',', range(50,75)), "\n";

Replies are listed 'Best First'.
Re: Re: mapping lists
by tall_man (Parson) on Jan 24, 2003 at 22:15 UTC
    I'd like to make a minor tweak to my solution. There's a sixth parameter "size" for binary_search, which is the point at which it reverts to a linear search, and it's defaulted to 512. That means the small @F array will be done with a linear search, after all.

    I set the size down and did one more optimization, as follows:

    my $lo_pos = binary_search(0,$#F,$lo,\&reader,\@F,2); my $hi_pos = binary_search($lo_pos,$#F,$hi,\&reader,\@F,2);
    I added a counter to the reader function and got the following output:
    Did 6 probes for low Did 6 probes for high 32,33,34,35 Did 6 probes for low Did 7 probes for high 50,51,52,53,54,55,56,57,58,59,60,61,62,63,64
    This is compared to a total of 78 probes the original way.