API: Add ArrayLib::flatten($array, $preserveKeys)

This commit is contained in:
Will Rossiter 2013-05-11 00:00:31 +12:00
parent 3b72432c40
commit 718108969b
2 changed files with 104 additions and 22 deletions

View File

@ -1,6 +1,8 @@
<?php <?php
/** /**
* Library of static methods for manipulating arrays. * Library of static methods for manipulating arrays.
*
* @package framework * @package framework
* @subpackage misc * @subpackage misc
*/ */
@ -43,7 +45,10 @@ class ArrayLib {
* @return array * @return array
*/ */
public static function invert($arr) { public static function invert($arr) {
if(!$arr) return false; if(!$arr) {
return false;
}
$result = array(); $result = array();
foreach($arr as $columnName => $column) { foreach($arr as $columnName => $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 * @param $arr array
* @return array * @return array
@ -70,6 +75,7 @@ class ArrayLib {
*/ */
public static function array_values_recursive($arr) { public static function array_values_recursive($arr) {
$lst = array(); $lst = array();
foreach(array_keys($arr) as $k) { foreach(array_keys($arr) as $k) {
$v = $arr[$k]; $v = $arr[$k];
if (is_scalar($v)) { if (is_scalar($v)) {
@ -80,92 +86,115 @@ class ArrayLib {
); );
} }
} }
return $lst; 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 $arr array
* @param $keys array * @param $keys array
*
* @return array * @return array
*/ */
public static function filter_keys($arr, $keys) public static function filter_keys($arr, $keys) {
{
foreach($arr as $key => $v) { foreach($arr as $key => $v) {
if(!in_array($key, $keys)) { if(!in_array($key, $keys)) {
unset($arr[$key]); unset($arr[$key]);
} }
} }
return $arr; return $arr;
} }
/** /**
* Determines if an array is associative by checking * Determines if an array is associative by checking for existing keys via
* for existing keys via array_key_exists(). * array_key_exists().
*
* @see http://nz.php.net/manual/en/function.is-array.php#76188 * @see http://nz.php.net/manual/en/function.is-array.php#76188
* *
* @param array $arr * @param array $arr
*
* @return boolean * @return boolean
*/ */
public static function is_associative($arr) { public static function is_associative($arr) {
if(is_array($arr) && ! empty($arr)) { if(is_array($arr) && ! empty($arr)) {
for($iterator = count($arr) - 1; $iterator; $iterator--) { 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 !array_key_exists(0, $arr);
} }
return false; return false;
} }
/** /**
* Recursively searches an array $haystack for the value(s) $needle. * Recursively searches an array $haystack for the value(s) $needle.
*
* Assumes that all values in $needle (if $needle is an array) are at * Assumes that all values in $needle (if $needle is an array) are at
* the SAME level, not spread across multiple dimensions of the $haystack. * the SAME level, not spread across multiple dimensions of the $haystack.
* *
* @param mixed $needle * @param mixed $needle
* @param array $haystack * @param array $haystack
* @param boolean $strict * @param boolean $strict
*
* @return boolean * @return boolean
*/ */
public static function in_array_recursive($needle, $haystack, $strict = false) { 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(!is_array($haystack)) {
return false;
}
if(in_array($needle, $haystack, $strict)) return true; // Is it in this level of the array? if(in_array($needle, $haystack, $strict)) {
else { return true;
foreach($haystack as $obj) { // It's not, loop over the rest of this array } else {
if(self::in_array_recursive($needle, $obj, $strict)) return true; 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. * Recursively merges two or more arrays.
* *
* Behaves similar to array_merge_recursive(), however it only merges values when both are arrays * Behaves similar to array_merge_recursive(), however it only merges
* rather than creating a new array with both values, as the PHP version does. The same behaviour * values when both are arrays rather than creating a new array with
* also occurs with numeric keys, to match that of what PHP does to generate $_REQUEST. * 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 * @return array
*/ */
public static function array_merge_recursive($array) { public static function array_merge_recursive($array) {
$arrays = func_get_args(); $arrays = func_get_args();
$merged = array(); $merged = array();
if(count($arrays) == 1) { if(count($arrays) == 1) {
return $array; return $array;
} }
while ($arrays) { while ($arrays) {
$array = array_shift($arrays); $array = array_shift($arrays);
if (!is_array($array)) { if (!is_array($array)) {
trigger_error('ArrayLib::array_merge_recursive() encountered a non array argument', E_USER_WARNING); trigger_error('ArrayLib::array_merge_recursive() encountered a non array argument', E_USER_WARNING);
return; return;
} }
if (!$array) { if (!$array) {
continue; continue;
} }
foreach ($array as $key => $value) { foreach ($array as $key => $value) {
if (is_array($value) && array_key_exists($key, $merged) && is_array($merged[$key])) { if (is_array($value) && array_key_exists($key, $merged) && is_array($merged[$key])) {
$merged[$key] = ArrayLib::array_merge_recursive($merged[$key], $value); $merged[$key] = ArrayLib::array_merge_recursive($merged[$key], $value);
@ -174,6 +203,30 @@ class ArrayLib {
} }
} }
} }
return $merged; 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;
}
}

View File

@ -1,9 +1,11 @@
<?php <?php
/** /**
* @package framework * @package framework
* @subpackage tests * @subpackage tests
*/ */
class ArrayLibTest extends SapphireTest { class ArrayLibTest extends SapphireTest {
public function testInvert() { public function testInvert() {
$arr = array( $arr = array(
'row1' => array( 'row1' => array(
@ -187,4 +189,31 @@ class ArrayLibTest extends SapphireTest {
'Numeric keys should behave like string keys' '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));
}
} }