From 718108969bbb3ab727b2740f4ca0781a431b3739 Mon Sep 17 00:00:00 2001 From: Will Rossiter Date: Sat, 11 May 2013 00:00:31 +1200 Subject: [PATCH] API: Add ArrayLib::flatten($array, $preserveKeys) --- core/ArrayLib.php | 97 ++++++++++++++++++++++++++++--------- tests/core/ArrayLibTest.php | 29 +++++++++++ 2 files changed, 104 insertions(+), 22 deletions(-) diff --git a/core/ArrayLib.php b/core/ArrayLib.php index 039f0eb70..3f35e3e2c 100644 --- a/core/ArrayLib.php +++ b/core/ArrayLib.php @@ -1,6 +1,8 @@ $column) { @@ -56,7 +61,7 @@ class ArrayLib { } /** - * Return an array where the keys are all equal to the values + * Return an array where the keys are all equal to the values. * * @param $arr array * @return array @@ -70,7 +75,8 @@ class ArrayLib { */ public static function array_values_recursive($arr) { $lst = array(); - foreach(array_keys($arr) as $k){ + + foreach(array_keys($arr) as $k) { $v = $arr[$k]; if (is_scalar($v)) { $lst[] = $v; @@ -80,92 +86,115 @@ class ArrayLib { ); } } + return $lst; } /** - * Filter an array by keys (useful for only allowing certain form-input to be saved). + * Filter an array by keys (useful for only allowing certain form-input to + * be saved). * * @param $arr array * @param $keys array + * * @return array */ - public static function filter_keys($arr, $keys) - { - foreach ($arr as $key => $v) { - if (!in_array($key, $keys)) { + public static function filter_keys($arr, $keys) { + foreach($arr as $key => $v) { + if(!in_array($key, $keys)) { unset($arr[$key]); } } + return $arr; } /** - * Determines if an array is associative by checking - * for existing keys via array_key_exists(). + * Determines if an array is associative by checking for existing keys via + * array_key_exists(). + * * @see http://nz.php.net/manual/en/function.is-array.php#76188 * * @param array $arr + * * @return boolean */ public static function is_associative($arr) { if(is_array($arr) && ! empty($arr)) { for($iterator = count($arr) - 1; $iterator; $iterator--) { - if (!array_key_exists($iterator, $arr)) return true; + if (!array_key_exists($iterator, $arr)) { + return true; + } } + return !array_key_exists(0, $arr); } + return false; } /** * Recursively searches an array $haystack for the value(s) $needle. + * * Assumes that all values in $needle (if $needle is an array) are at * the SAME level, not spread across multiple dimensions of the $haystack. * * @param mixed $needle * @param array $haystack * @param boolean $strict + * * @return boolean */ public static function in_array_recursive($needle, $haystack, $strict = false) { - if(!is_array($haystack)) return false; // Not an array, we've gone as far as we can down this branch - - if(in_array($needle, $haystack, $strict)) return true; // Is it in this level of the array? - else { - foreach($haystack as $obj) { // It's not, loop over the rest of this array - if(self::in_array_recursive($needle, $obj, $strict)) return true; + if(!is_array($haystack)) { + return false; + } + + if(in_array($needle, $haystack, $strict)) { + return true; + } else { + foreach($haystack as $obj) { + if(self::in_array_recursive($needle, $obj, $strict)) { + return true; + } } } - return false; // Never found $needle :( + return false; } /** * Recursively merges two or more arrays. * - * Behaves similar to array_merge_recursive(), however it only merges values when both are arrays - * rather than creating a new array with both values, as the PHP version does. The same behaviour - * also occurs with numeric keys, to match that of what PHP does to generate $_REQUEST. + * Behaves similar to array_merge_recursive(), however it only merges + * values when both are arrays rather than creating a new array with + * both values, as the PHP version does. The same behaviour also occurs + * with numeric keys, to match that of what PHP does to generate $_REQUEST. + * + * @param array $array * - * @param array $array, ... * @return array */ public static function array_merge_recursive($array) { $arrays = func_get_args(); $merged = array(); + if(count($arrays) == 1) { return $array; } + while ($arrays) { $array = array_shift($arrays); + if (!is_array($array)) { trigger_error('ArrayLib::array_merge_recursive() encountered a non array argument', E_USER_WARNING); return; } + if (!$array) { continue; } + foreach ($array as $key => $value) { if (is_array($value) && array_key_exists($key, $merged) && is_array($merged[$key])) { $merged[$key] = ArrayLib::array_merge_recursive($merged[$key], $value); @@ -174,6 +203,30 @@ class ArrayLib { } } } + return $merged; } + + /** + * Takes an multi dimension array and returns the flattened version. + * + * @param array $array + * @param boolean $preserveKeys + * + * @return array + */ + public static function flatten($array, $preserveKeys = true, &$out = array()) { + foreach($array as $key => $child) { + if(is_array($child)) { + $out = self::flatten($child, $preserveKeys, $out); + } else if($preserveKeys) { + $out[$key] = $child; + } else { + $out[] = $child; + } + } + + return $out; + } } + \ No newline at end of file diff --git a/tests/core/ArrayLibTest.php b/tests/core/ArrayLibTest.php index 1376129ec..356436c83 100644 --- a/tests/core/ArrayLibTest.php +++ b/tests/core/ArrayLibTest.php @@ -1,9 +1,11 @@ array( @@ -187,4 +189,31 @@ class ArrayLibTest extends SapphireTest { 'Numeric keys should behave like string keys' ); } + + public function testFlatten() { + $options = array( + '1' => 'one', + '2' => 'two' + ); + + $expected = $options; + + $this->assertEquals($expected, ArrayLib::flatten($options)); + + $options = array( + '1' => array( + '2' => 'two', + '3' => 'three' + ), + '4' => 'four' + ); + + $expected = array( + '2' => 'two', + '3' => 'three', + '4' => 'four' + ); + + $this->assertEquals($expected, ArrayLib::flatten($options)); + } }