search then returns the first record in the file that is not earlier than the desired record, and leaves the filehandle positioned at that record. If there is no such record, it returns undef.
For example, suppose you want to search the dictionary file for words that begin with foo. You might:sub search { my ($fh, $cmp) = @_; my ($lo, $hi) = (0, -s $fh); while (1) { my $mid = int(($lo + $hi)/2); if ($mid) { seek $fh, $mid-1, SEEK_SET; my $junk = <$fh>; } else { seek $fh , $mid, SEEK_SET; } my $start = tell $fh; my $rec = <$fh>; return unless defined $rec; chomp($rec); if ($hi == $lo) { seek $fh, $start, SEEK_SET; return $rec }; local $_ = $rec; if ($cmp->($rec) < 0) { $lo = $mid+1 } else { $hi = $mid } } }
The search call moves the filehandle quickly to the first record that begins with foo, and then the while loop prints out the words, quitting after the last one. Using search is quicker than scanning the file from the beginning looking for the first foo word, unless the file is very small.open DICT, "<", "/usr/dict/Web2" or die...; if (search(\*DICT, sub { lc $_ cmp "foo" })) { # DICT is now positioned at the first word beginning with 'foo' while (<DICT>) { last unless /^foo/i; print; } }
The behavior is similar to that of the standard Search::Dict module, but the code is much simpler, and I think my interface is more flexible. I wrote this as an example for my new class Strategies for Lightweight Databases. Share and enjoy!
--
Mark Dominus
Perl Paraphernalia
In reply to Re: Binary searching with Perl.
by Dominus
in thread Binary searching with Perl.
by DigitalKitty
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |