note 101932 modified in function.array-search by danbrown
| From: | danbrown@php.net | Date: | Wed, 19 Jan 2011 19:19:55 +0000 |
| Subject: | note 101932 modified in function.array-search by danbrown | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-175906@lists.php.net to get a copy of this message | ||
Recently I had to get all locations of a one-dimensional non-associative array (needle, not array of
needles) in another one-dimensional non-associative array (haystack) without using more memory than
necessary. I haven't found any satisfactory way to do that, so I wrote the following function,
inspired by the array_slice() source code.
Notes:
0. $offset, $length and $strict behave the same way as those for array_slice() and array_search();
1. this function doesn't use foreach or array_slice(), neither does it modify $needle or
$haystack, so no temporary copies are needed/created, regardless of whether the arguments are passed
by reference or not -- useful when dealing with very large haystacks and needles;
2. $needle and $haystack are typecast to array if they're not arrays;
3. you can specify the $start position to start searching from in the $haystack (default is 0);
4. negative $start values can be used if you want to specify the starting position from the end of
$haystack.
5. you can specify the search $length, starting from $start; a negative value stops the search at
that many elements from the end of the haystack;
6. pass true as the fifth argument to do a strict search (not tested on objects);
7. the function returns an array if it finds one or more occurrences of $needle in the $haystack,
false on failure.
8. keys are preserved;
9. if you want to get only the first location of $needle in $haystack, returned as an integer rather
than array -- in other words, to make an array_match() function instead of array_match_all() --
remove this line:
$results = array();
and replace:
if ($found)
{
$results[] = $i;
$i += $ncount - 1;
}
}
if (!empty($results))
return $results;
else
return false;
with:
if ($found)
return $i;
}
return false;
And now the function:
<?php
function array_match_all($needle, $haystack, $offset = 0, $length = 0, $strict = false)
{
if (!is_array($needle))
$needle = (array) $needle;
if (!is_array($haystack))
$haystack = (array) $haystack;
$offset = (int) $offset;
$length = (int) $length;
$strict = ($strict != false);
$ncount = count($needle);
$hcount = count($haystack);
// Empty arrays? Really? Also, no point in dealing with a needle larger than the haystack.
if (($hcount == 0) || ($ncount == 0) || ($ncount > $hcount))
return false;
// Is offset beyond the upper bound?
if ($offset > $hcount - $ncount)
return false;
// If offset is specified from the end of haystack, is it beyond the lower bound?
elseif ($offset < 0 && ($offset = $hcount + $offset) < 0)
$offset = 0;
// Determine the length.
if ($length == 0)
$length = $hcount;
if ($length < 0)
$length = $hcount - $offset + $length;
elseif ($offset + $length > $hcount)
$length = $hcount - $offset;
// Is the needle larger than the portion of the haystack we are searching in?
if (($length <= 1) || ($ncount > $length))
return false;
// Determine the actual search length.
$length = $offset + $length - $ncount + 1;
$results = array();
for ($i = $offset; $i < $length; ++$i)
{
$found = true;
for ($j = 0; $j < $ncount; ++$j)
{
if (($strict && ($haystack[$i + $j] !== $needle[$j])) || (!$strict &&
($haystack[$i + $j] != $needle[$j])))
{
$found = false;
break;
}
}
if ($found)
{
$results[] = $i;
$i += $ncount;
}
}
if (empty($results))
return false;
else
return $results;
}
?>
--was--
Recently I had to get all locations of a one-dimensional non-associative array (needle, not array of
needles) in another one-dimensional non-associative array (haystack) without using more memory than
necessary. I haven't found any satisfactory way to do that, so I wrote the following function,
inspired by the array_slice() source code.
Notes:
0. $offset, $length and $strict behave the same way as those for array_slice() and array_search();
1. this function doesn't use foreach or array_slice(), neither does it modify $needle or
$haystack, so no temporary copies are needed/created, regardless of whether the arguments are passed
by reference or not -- useful when dealing with very large haystacks and needles;
2. $needle and $haystack are typecast to array if they're not arrays;
3. you can specify the $start position to start searching from in the $haystack (default is 0);
4. negative $start values can be used if you want to specify the starting position from the end of
$haystack.
5. you can specify the search $length, starting from $start; a negative value stops the search at
that many elements from the end of the haystack;
6. pass true as the fifth argument to do a strict search (not tested on objects);
7. the function returns an array if it finds one or more occurrences of $needle in the $haystack,
false on failure.
8. keys are preserved;
9. if you want to get only the first location of $needle in $haystack, returned as an integer rather
than array -- in other words, to make an array_match() function instead of array_match_all() --
remove this line:
$results = array();
and replace:
if ($found)
{
$results[] = $i;
$i += $ncount;
}
}
if (!empty($results))
return $results;
else
return false;
with:
if ($found)
return $i;
}
return false;
And now the function:
<?php
function array_match_all($needle, $haystack, $offset = 0, $length = 0, $strict = false)
{
if (!is_array($needle))
$needle = (array) $needle;
if (!is_array($haystack))
$haystack = (array) $haystack;
$offset = (int) $offset;
$length = (int) $length;
$strict = ($strict != false);
$ncount = count($needle);
$hcount = count($haystack);
// Empty arrays? Really? Also, no point in dealing with a needle larger than the haystack.
if (($hcount == 0) || ($ncount == 0) || ($ncount > $hcount))
return false;
// Is offset beyond the upper bound?
if ($offset > $hcount - $ncount)
return false;
// If offset is specified from the end of haystack, is it beyond the lower bound?
elseif ($offset < 0 && ($offset = $hcount + $offset) < 0)
$offset = 0;
// Determine the length.
if ($length == 0)
$length = $hcount;
if ($length < 0)
$length = $hcount - $offset + $length;
elseif ($offset + $length > $hcount)
$length = $hcount - $offset;
// Is the needle larger than the portion of the haystack we are searching in?
if (($length <= 1) || ($ncount > $length))
return false;
// Determine the actual search length.
$length = $offset + $length - $ncount + 1;
$results = array();
for ($i = $offset; $i < $length; ++$i)
{
$found = true;
for ($j = 0; $j < $ncount; ++$j)
{
if (($strict && ($haystack[$i + $j] !== $needle[$j])) || (!$strict &&
($haystack[$i + $j] != $needle[$j])))
{
$found = false;
break;
}
}
if ($found)
{
$results[] = $i;
$i += $ncount;
}
}
if (empty($results))
return false;
else
return $results;
}
?>
http://php.net/manual/en/function.array-search.php