note 101932 modified in function.array-search by danbrown

From: Date: Wed, 19 Jan 2011 22:09:41 +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-175912@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 - 1; } } 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 - 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; } ?> http://php.net/manual/en/function.array-search.php

« previous php.notes (#175912) next »