Browse Source

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.
Hunter Perrin 11 years ago
parent
commit
00bc228db5
1 changed files with 41 additions and 12 deletions
  1. 41 12
      src/Utility/Hash.php

+ 41 - 12
src/Utility/Hash.php

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