Improvements to Hash::expand and Hash::merge.

Because of the recursion in these functions, processing very large
arrays would take a very long time. I rewrote the functions to
eliminate any unnecessary recursion and function calls. Large arrays
are now processed much faster.
This commit is contained in:
Hunter Perrin 2014-10-01 11:22:44 -07:00
parent eac4e3d6ee
commit 050e368bd0

View file

@ -622,6 +622,9 @@ class Hash {
*/ */
public static function expand($data, $separator = '.') { public static function expand($data, $separator = '.') {
$result = array(); $result = array();
$stack = array();
foreach ($data as $flat => $value) { foreach ($data as $flat => $value) {
$keys = explode($separator, $flat); $keys = explode($separator, $flat);
$keys = array_reverse($keys); $keys = array_reverse($keys);
@ -634,7 +637,24 @@ class Hash {
$k => $child $k => $child
); );
} }
$result = self::merge($result, $child);
$stack[] = array($child, &$result);
while (!empty($stack)) {
foreach ($stack as $curKey => &$curMerge) {
foreach ($curMerge[0] as $key => &$val) {
if (!empty($curMerge[1][$key]) && (array)$curMerge[1][$key]===$curMerge[1][$key] && (array)$val===$val) {
$stack[] = array(&$val, &$curMerge[1][$key]);
} elseif ((int)$key===$key && isset($curMerge[1][$key])) {
$curMerge[1][] = $val;
} else {
$curMerge[1][$key] = $val;
}
}
unset($stack[$curKey]);
}
unset($curMerge);
}
} }
return $result; return $result;
} }
@ -654,19 +674,28 @@ class Hash {
* @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::merge * @link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::merge
*/ */
public static function merge(array $data, $merge) { public static function merge(array $data, $merge) {
$args = func_get_args(); $args = array_slice(func_get_args(), 1);
$return = current($args); $return = $data;
while (($arg = next($args)) !== false) { foreach ($args as &$curArg) {
foreach ((array)$arg as $key => $val) { $stack[] = array((array)$curArg, &$return);
if (!empty($return[$key]) && is_array($return[$key]) && is_array($val)) { }
$return[$key] = self::merge($return[$key], $val); unset($curArg);
} elseif (is_int($key) && isset($return[$key])) {
$return[] = $val; while (!empty($stack)) {
foreach ($stack as $curKey => &$curMerge) {
foreach ($curMerge[0] as $key => &$val) {
if (!empty($curMerge[1][$key]) && (array)$curMerge[1][$key]===$curMerge[1][$key] && (array)$val===$val) {
$stack[] = array(&$val, &$curMerge[1][$key]);
} elseif ((int)$key===$key && isset($curMerge[1][$key])) {
$curMerge[1][] = $val;
} else { } else {
$return[$key] = $val; $curMerge[1][$key] = $val;
} }
} }
unset($stack[$curKey]);
}
unset($curMerge);
} }
return $return; return $return;
} }