binary_range_search
私は次のように呼ばれる関数を持っています:
my $brs_iterator = binary_range_search(
target => $range, # eg. [1, 200]
search => $ranges # eg. [ {start => 1, end => 1000},
); # {start => 500, end => 1500} ]
brs_iterator->()
$rangeがオーバーラップするすべての@$rangeを繰り返し処理します。
binary_range_search
複数の範囲をターゲットとして呼び出すことができるように拡張したいと思います。例:
target => $target_ranges # eg. [ [1, 200], [50, 300], ... ]
search => $search_ranges # as above
したがって、$ range-> [0]の検索が終了すると、$range->[1]などに移動する必要があります。問題の関数は、元の形式で次のようになります。
sub binary_range_search {
my %options = @_;
my $range = $options{target} || return;
my $ranges = $options{search} || return;
my ( $low, $high ) = ( 0, @{$ranges} - 1 );
while ( $low <= $high ) {
my $try = int( ( $low + $high ) / 2 );
$low = $try + 1, next if $ranges->[$try]{end} < $range->[0];
$high = $try - 1, next if $ranges->[$try]{start} > $range->[1];
my ( $down, $up ) = ($try) x 2;
my %seen = ();
my $brs_iterator = sub {
if ( $ranges->[ $up + 1 ]{end} >= $range->[0]
and $ranges->[ $up + 1 ]{start} <= $range->[1]
and !exists $seen{ $up + 1 } )
{
$seen{ $up + 1 } = undef;
return $ranges->[ ++$up ];
}
elsif ( $ranges->[ $down - 1 ]{end} >= $range->[0]
and $ranges->[ $down + 1 ]{start} <= $range->[1]
and !exists $seen{ $down - 1 }
and $down > 0 )
{
$seen{ $down - 1 } = undef;
return $ranges->[ --$down ];
}
elsif ( !exists $seen{$try} ) {
$seen{$try} = undef;
return $ranges->[$try];
}
else {
return;
}
};
return $brs_iterator;
}
return sub { };
}
重複する範囲が見つかるまで、これは標準の二分探索戦略です。次に、それは右に移動し、それを使い果たし、左に動き、それを使い果たし、そして最後に諦めます。理想的には、それはおそらくshift
次のターゲット範囲であり、検索をやり直す必要があります(おそらく再帰を介して?)。私の問題は、イテレータ構造でそれを機能させる方法がわからないことです。