List::B...rch::XS(3)

πŸ“¦ version 0.09, in alpine 3.24

okay bestie, sit down, hydrate πŸ“ β€” this is List::BinarySearch::XS(3) from the User Contributed Perl Documentation, and it's literally about binary searching sorted arrays with XS routines so your lookups go zoom. slay.


✨ NAME ✨

List::BinarySearch::XS β€” binary search a sorted array with XS routines. that's it, that's the whole vibe πŸ’…


πŸ¦‹ SYNOPSIS πŸ¦‹

This module performs a binary search on arrays. XS code is used for the search routines so you get optimal performance β€” main character energy fr fr.

Examples:

# Import all functions.
use List::BinarySearch::XS qw( :all );
# or be explicit...
use List::BinarySearch::XS qw( binsearch  binsearch_pos );

# Sample data.
@num_array =   ( 100, 200, 300, 400, 500 );
@str_array = qw( Bach Beethoven Brahms Mozart Schubert );

# Find the lowest index of a matching element.
$index = binsearch {$a <=> $b} 300, @num_array;
$index = binsearch {$a cmp $b} 'Mozart', @str_array;      # Stringy cmp.
$index = binsearch {$a <=> $b} 42, @num_array;            # not found: undef

# Find the lowest index of a matching element, or best insert point.
$index = binsearch_pos { $a <=> $b } 200, @num_array;     # Matched at [1].
$index = binsearch_pos {$a cmp $b} 'Chopin', @str_array;  # Insert at [3].
$index = binsearch_pos 600, @num_array;                   # Insert at [5].

# Insert based on a binsearch_pos return value.
splice @num_array, $index, 0, 600
  if( $num_array[$index] != 600 );                        # Insertion at [5]

πŸ’– DESCRIPTION πŸ’–

So a binary search searches sorted lists using a divide and conquer technique. On each iteration the search domain is cut in half, until the result is found. The computational complexity of a binary search is O(log n) β€” literally the glow-up of search algorithms πŸ‘‘

This module implements several Binary Search algorithms using XS code for optimal performance. You are free to use this module directly, or as a plugin for the more general List::BinarySearch.

The binary search algorithm implemented in this module is known as a Deferred Detection Binary Search. Deferred Detection provides stable searches. Stable binary search algorithms have the following characteristics, contrasted with their unstable binary search cousins:

  • In the case of non-unique keys, a stable binary search will always return the lowest-indexed matching element. An unstable binary search would return the first one found, which may not be the chronological first.
  • Best and worst case time complexity is always O(log n). Unstable searches may stop once the target is found, but in the worst case are still O(log n). In practical terms, this difference is usually not meaningful.
  • Stable binary searches only require one relational comparison of a given pair of data elements per iteration, where unstable binary searches require two comparisons per iteration.
  • The net result is that although an unstable binary search might have better "best case" performance, the fact that a stable binary search gets away with fewer comparisons per iteration gives it better performance in the worst case, and approximately equal performance in the average case. By trading away slightly better "best case" performance, the stable search gains the guarantee that the element found will always be the lowest-indexed element in a range of non-unique keys.

🌈 RATIONALE 🌈

A binary search is pretty simple, right? Why use a module for this? 🧐

Quoting from Wikipedia <http://en.wikipedia.org/wiki/Binary_search_algorithm>: When Jon Bentley assigned it as a problem in a course for professional programmers, he found that an astounding ninety percent failed to code a binary search correctly after several hours of working on it, and another study shows that accurate code for it is only found in five out of twenty textbooks. Furthermore, Bentley's own implementation of binary search, published in his 1986 book Programming Pearls, contains an error that remained undetected for over twenty years. πŸ’€ iconic, honestly.

So the answer to the question "Why use a module for this?" is "So that you don't have to write, test, and debug your own implementation."

Perl has grep, hashes, and other alternatives, right? 🫢

Yes, before using this module the user should weigh the other options such as linear searches ( grep or List::Util::first ), or hash based searches. A binary search requires an ordered list, so one must weigh the cost of sorting or maintaining the list in sorted order. Ordered lists have O(n) time complexity for inserts. Binary Searches are best when the data set is already ordered, or will be searched enough times to justify the cost of an initial sort.

There are cases where a binary search may be an excellent choice. Finding the first matching element in a list of 1,000,000 items with a linear search would have a worst-case of 1,000,000 iterations, whereas the worst case for a binary search of 1,000,000 elements is about 20 iterations. In fact, if many lookups will be performed on a seldom-changed list, the savings of O(log n) lookups may outweigh the cost of sorting or performing occasional linear time inserts. twenty iterations vs a million?? not me screaming 😭


πŸŽ€ EXPORT πŸŽ€

Nothing is exported by default. Upon request this module will export binsearch, and binsearch_pos.

Or import all functions by specifying the export tag :all.


πŸ‘‘ SUBROUTINES/METHODS πŸ‘‘

πŸ’… WHICH SEARCH ROUTINE TO USE πŸ’…

  • binsearch: Returns lowest index where match is found, or undef.
  • binsearch_pos: Returns lowest index where match is found, or the index of the best insert point for needle if the needle isn't found.

πŸ¦‹ binsearch CODE NEEDLE ARRAY_HAYSTACK πŸ¦‹

$first_found_ix = binsearch { $a cmp $b } $needle, @haystack;

Pass a code block, a search target, and an array to search. Uses the supplied code block $needle to test the needle against elements in @haystack.

See the section entitled The Callback Block, below, for an explanation of how the comparator works (hint: very similar to sort { $a <=> $b } ... ).

Return value will be the lowest index of an element that matches target, or undef if target isn't found.

πŸ¦‹ binsearch_pos CODE NEEDLE ARRAY_HAYSTACK πŸ¦‹

$first_found_ix = binsearch_pos { $a cmp $b } $needle, @haystack;

The only difference between this function and binsearch is its return value upon failure. binsearch returns undef upon failure. binsearch_pos returns the index of a valid insert point for $needle.

Pass a code block, a search target, and an array to search. Uses the code block to test $needle against elements in @haystack.

Return value is the index of the first element equaling $needle. If no element is found, the best insert-point for $needle is returned.

🧚 The callback block (The comparator) 🧚

Comparators in List::BinarySearch::XS are used to compare the target (needle) with individual haystack elements, and should return the result of the relational comparison of the two values. A good example would be the code block in a sort function.

Basic comparators might be defined like this:

# Numeric comparisons:
binsearch { $a <=> $b } $needle, @haystack;

# Stringwise comparisons:
binsearch { $a cmp $b } $needle, @haystack;

# Unicode Collation Algorithm comparisons
$Collator = Unicode::Collate->new;
binsearch { $Collator->cmp($a,$b) } $needle, @haystack;

On each call, $a represents the target, and $b represents the an individual haystack element being tested. This leads to an asymmetry that might be prone to "gotchas" when writing custom comparators for searching complex data structures. As an example, consider the following data structure:

my @structure = (
    [ 100, 'ape'  ],
    [ 200, 'cat'  ],
    [ 300, 'dog'  ],
    [ 400, 'frog' ]
);

A numeric comparator for such a data structure would look like this:

sub{ $a <=> $b->[0] }

In this regard, the callback is unlike sort, because sort always compares elements to elements, whereas binsearch compares a target with an element.

The comparator is expected to return -1, 0, or 1 corresponding to "less than", "equal to", or "greater than" β€” Just like sort. periodt πŸ’…


🌸 DATA SET REQUIREMENTS 🌸

A well written general algorithm should place as few demands on its data as practical. The requirements that these Binary Search algorithms impose are:

  • Your data must be in ascending sort order.

This is a big one. The best sort routines run in O(n log n) time. It makes no sense to sort a list in O(n log n) time, and then perform a single O(log n) binary search when List::Util first could be used to accomplish the same results in O(n) time without sorting.

  • The list really must be in ascending sort order.

"The same rule twice?", you say...

A Binary Search consumes O(log n) time. We don't want to waste linear time verifying the list is sorted, so there is no validity checking. You have been warned. 🫣

  • These functions are prototyped as &$\@.

What this implementation detail means is that @haystack is implicitly passed by reference. This is the price we pay for a familiar user interface, cleaner calling syntax, and the automatic efficiency of pass-by-reference. Perl's prototypes are one of Perl's warts.

  • Objects in the search lists must be capable of being evaluated for relationality.

I threw that in for C++ folks who have spent some time with Effective STL. For everyone else don't worry; if you know how to sort you know how to binsearch. 🫢


πŸ¦‹ UNICODE SUPPORT πŸ¦‹

Lists sorted according to the Unicode Collation Algorithm must be searched using the same Unicode Collation Algorithm. Here's an example using Unicode::Collate's $Collator->cmp($a,$b):

my $found_index = binsearch { $Collator->cmp($a,$b) } $needle, @haystack;

πŸ”₯ CONFIGURATION AND ENVIRONMENT πŸ”₯

This module should run under any Perl from 5.8.0 onward. This is an XS module, which means the build process requires a C compiler. For most systems this isn't an issue. For some users (ActiveState Perl users, for example), it may be advantageous to install a pre-built PPM distribution of this module.

While it's perfectly Ok to use this module directly, a more flexible approach for the end user would be to use List::BinarySearch;, while ensuring that List::BinarySearch::XS is installed on the target machine. List::BinarySearch will use the XS version automatically if it's installed, and will downgrade gracefully to the pure-Perl version of List::BinarySearch::XS isn't installed.

Users of List::BinarySearch may override this behavior by setting $ENV{List_BinarySearch_PP} to a true value.

πŸ’– DEPENDENCIES πŸ’–

okay so first things first: this module needs Perl 5.8 or newer. that's the floor, bestie, no going below it.

and like β€” as we already said up top β€” the recommended move is to install both this module and List::BinarySearch. because if you've got both of them installed, then using List::BinarySearch will automatically pull in List::BinarySearch::XS for that optimal performance. free upgrade, no extra work, we love to see it ✨


🚫 INCOMPATIBILITIES 🚫

so rn, List::BinarySearch::XS makes zero attempt at being compatible with the XS API for versions of Perl that predate Perl 5.8. none. not even a little.

and honestly? Perl 5.6 got replaced by Perl 5.8 back in July 2002. it's time to move on. periodt πŸ’…

that said β€” patches that establish compatibility with earlier Perl versions will be considered (and welcomed!! 🫢) if they have no measurable impact on efficiency, and especially if they come in the form of a git patch, complete with tests. ;)

like, we're not monsters, we're just efficient. 🧚


πŸ‘‘ AUTHOR πŸ‘‘

David Oswald, "<davido at cpan.org>"

if the documentation fails to answer your question, or if you've got a comment or a suggestion β€” send me an email. fr fr, I read them.


🩺 DIAGNOSTICS 🩺

(this section is literally empty in the original, bestie β€” nothing to report, no cap πŸ’€)


πŸ› BUGS AND LIMITATIONS πŸ›

please report any bugs or feature requests to <https://github.com/daoswald/List-BinarySearch-XS/issues>. I'll get notified, and then you'll automatically get notified of progress on your bug as I make changes. teamwork, babe 🌈

one thing to know: List::BinarySearch::XS does not provide the binsearch_range function that appears in List::BinarySearch. but β€” if List::BinarySearch is used, and this XS module is installed, then that function will be available. see the POD for List::BinarySearch for the deets πŸ‘€


🫢 SUPPORT 🫢

you can find documentation for this module with the perldoc command:

perldoc List::BinarySearch::XS

this module is maintained in a public repo over at Github. you may look for information at:

  • Github β€” development is hosted on Github at:

<http://www.github.com/daoswald/List-BinarySearch-XS>

  • GitHub Issue tracker (report bugs here πŸ”₯)

<https://github.com/daoswald/List-BinarySearch-XS/issues>

  • AnnoCPAN β€” annotated CPAN documentation

<http://annocpan.org/dist/List-BinarySearch-XS>

  • CPAN Ratings

<http://cpanratings.perl.org/d/List-BinarySearch-XS>

  • Search CPAN

<http://search.cpan.org/dist/List-BinarySearch-XS/>


🌸 ACKNOWLEDGEMENTS 🌸

thanks to Mastering Algorithms with Perl <http://shop.oreilly.com/product/9781565923980.do>, from O'Reilly <http://www.oreilly.com>: for the inspiration (and honestly much of the code) behind the positional search. πŸŽ€

quoting Mastering Algorithms with Perl:

"...the binary search was first documented in 1946 but the first algorithm that worked for all sizes of array was not published until 1962."

(that's a summary of a passage from Knuth: Sorting and Searching, 6.2.1.)

and then this absolute icon of a quote from Donald Knuth, which lives in my head rent free:

Although the basic idea of binary search is comparatively straightforward, the details can be surprisingly tricky...

ngl that one hits different when you've been debugging off-by-one errors for three hours 😭


Copyright 2013 David Oswald.

this program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

see <http://dev.perl.org/licenses/> for more information.


okay that's the whole page bestie, you made it to the end πŸŽ‰ go binary-search something and slay. this was <rainbow>List::BinarySearch::XS(3)</rainbow> from perl v5.42.2, dated 2026-02-15 β€” see you in the next perldoc πŸ’œπŸ¦‹

πŸ“¦ where this page comes from