note 106022 added to function.array-search
| From: | gtrevg at gmail dot com | Date: | Mon, 03 Oct 2011 20:21:52 +0000 |
| Subject: | note 106022 added to function.array-search | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-183616@lists.php.net to get a copy of this message | ||
There's a small bug in temporal dot pl's Array_BinarySearch() function (thanks for posting
it, BTW). I have found that sometimes the $probe that gets returned is where the item should be
inserted and sometimes it's the item just before it should be inserted.
Here's a use case that illustrates the issue:
<?php
$haystack = array( "a", "b", "c", "d", "e");
$needle = "ca";
$res = Array_BinarySearch( $needle, $haystack, 'strcmp', $probe);
echo (int)$res . ' ' . $probe . '<br />';
// output is: 0 3 -- thinks it should be inserted at position 3 = GOOD
$needle = "bb";
$res = Array_BinarySearch( $needle, $haystack, 'strcmp', $probe);
echo (int)$res . ' ' . $probe . '<br />';
// output is: 0 1 -- thinks it should be inserted at position 1 = BAD
?>
If we output the values for each High, Low, Probe, and Comparison for each round we get:
H: 4, L: 0, P: 2, C: <
H: 4, L: 3, P: 3, C: >
res: 0, probe: 3
H: 4, L: 0, P: 2, C: >
H: 1, L: 0, P: 0, C: <
H: 1, L: 1, P: 1, C: <
res: 0, probe: 1
So, in order to handle this last case where "bb" should actually be inserted in position
2, I've modified the function to have a different comparison:
<?php
function Array_BinarySearch( $needle, $haystack, $comparator , &$probe )
{
$high = Count( $haystack ) -1;
$low = 0;
while ( $high >= $low )
{
$probe = Floor( ( $high + $low ) / 2 );
$comparison = $comparator( $haystack[$probe], $needle );
if ( $comparison < 0 )
{
$low = $probe +1;
}
elseif ( $comparison > 0 )
{
$high = $probe -1;
}
else
{
return true;
}
}
//The loop ended without a match
// Adjust probe if it > than currently indexed value
if ($comparator($needle, $haystack[$probe]) > 0) {
$probe++;
}
return false;
}
?>
This comparison also handles the case where the found element would end up being after the last
element. Running with a needle of "zz" produces a probe value of 5:
H: 4, L: 0, P: 2, C: <
H: 4, L: 3, P: 3, C: <
H: 4, L: 4, P: 4, C: <
res: 0, probe: 5
----
Server IP: 69.147.83.197
Probable Submitter: 204.15.240.18
----
Manual Page -- http://www.php.net/manual/en/function.array-search.php
Edit -- https://master.php.net/note/edit/106022
Del: integrated -- https://master.php.net/note/delete/106022/integrated
Del: useless -- https://master.php.net/note/delete/106022/useless
Del: bad code -- https://master.php.net/note/delete/106022/bad+code
Del: spam -- https://master.php.net/note/delete/106022/spam
Del: non-english -- https://master.php.net/note/delete/106022/non-english
Del: in docs -- https://master.php.net/note/delete/106022/in+docs
Del: other reasons-- https://master.php.net/note/delete/106022
Reject -- https://master.php.net/note/reject/106022
Search -- https://master.php.net/manage/user-notes.php