I have a multi-level Array. Number of levels (sub-arrays) isn't known. It could be only two, but also could be 5. The only thing I know - there are certain (known) keys on each level.
Let consider following example:
Array
(
[number] => 21
[otherkey] => value
[sub] => Array
(
[count] =>
[number] => 29
[some] => thing
[range] => Array
(
...
)
[sub] => Array
(
[count] => 1
[number] => 16
[key] => value
[date] => 2013-07-25
[sub] => Array
(
[count] => 0
[number] => 4
[key] => value
[sub] => Array
(
[count] => 1
[number] => 24
[key] => value
[sub] => last
)
)
)
)
)
My goal is to iterate through all 'number'
keys and create text like 'even' or 'odd', but the result should be saved under own key (say number_str
) on each level
So modified Array should look like this:
Array
(
[number] => 21
[otherkey] => value
[sub] => Array
(
[count] =>
[number] => 29
[some] => thing
[range] => Array
(
...
)
[sub] => Array
(
[count] => 1
[number] => 16
[key] => value
[date] => 2013-07-25
[sub] => Array
(
[count] => 0
[number] => 4
[key] => value
[sub] => Array
(
[count] => 1
[number] => 24
[key] => value
[sub] => last
[number_str] => even //new key
)
[number_str] => even //new key
)
[number_str] => even //new key
)
[number_str] => odd //new key
)
[number_str] => odd //new key
)
So I tried to use RecursiveIteratorIterator
$rai = new RecursiveArrayIterator($data);
$rii = new RecursiveIteratorIterator($rai);
foreach ($rii as $idx => $level) {
if($idx === 'number')
{
$str = ($level % 2) ? 'odd' : 'even';
$rii->offsetSet('number_str', $str);
}
}
but it didn't worked. So I found kind of 'workaround'. It seems to do, what I expect if each Sub-Array is an Object of stdClass
convert the original Array (and all sub-array) to a stdClass
$data = json_encode(json_decode($data)); // ..dirty gimmick. Possible performance killer ?
$rai = new RecursiveArrayIterator($data);
$rii = new RecursiveIteratorIterator($rai);
foreach ($rii as $idx => $level) {
//same logic as above...
}
var_dump($rai);
now it looks like I have wished results, the only problem is, all sub-level now are instances of stdClass
code online -> http://ideone.com/PIiZOX
QUESTION Is there a way to get the same results, but without the gimmick with json_decode
/ json_encode
so the output will be a normal Array ?
PS : I know, there is array_walk()
but it's not an option
UPDATE: I should mention that the question is not about getting correct results. I know, that custom recursiv function (and maybe array_walk_recursive
()) will do the trick. Its more about SPLs RecursiveIterators as possible solutuion. I just wonder myself, why it does work with strClass
es and why don't with regular Array.
The example Array from obeve isn't real use-case. As you may guess, the real use-case are Arrays (sometimes more than 600 rows) with data from DB. Some of them have sub-arrays. The only thing i know are keys which should be modified (by a given rule). Performance is a main criteria
Try with a custom recursive function:
function addEvenOrOdd(&$array) {
$array['number_str'] = ($array['number'] % 2) ? 'odd' : 'even';
ksort($array);
if(isset($array['sub']) && is_array($array['sub'])) {
addEvenOrOdd($array['sub']);
}
}
addEvenOrOdd($yourarray);
See it working live here: http://codepad.viper-7.com/vBc42b
I think it's not need to use RecursiveArrayIterator, simple recursive function will be enough. Hope this will helps:
function iterate_recursive( &$target_arr ){
$val = 'odd';
if( $target_arr[ 'number' ] % 2 == 0 ){
$val = 'even';
}
$target_arr[ 'number_str' ] = $val;
if( array_key_exists( 'sub', $target_arr ) and is_array($target_arr['sub'])){
iterate_recursive( $target_arr[ 'sub' ] );
}
}
$dta_arr = Array
(
'number' => 21,
'otherkey' => 'value',
'sub' => Array
(
'count' => 123,
'number' => 29,
'some' => 'thing',
'range' => Array
(
'stub' => False,
),
'sub' => Array
(
'count' => 1,
'number' => 16,
'key' => 'value',
'date' => 2013 - 07 - 25,
'sub' => Array
(
'count' => 0,
'number' => 4,
'key' => 'value',
'sub' => Array
(
'count' => 1,
'number' => 24,
'key' => 'value',
'sub' => 'thing',
)
),
),
),
);
iterate_recursive( $dta_arr );
print_r($dta_arr);
function even_or_odd(&$arr){
if(is_array($arr)){
if (isset($arr['number'])){
if ($arr['number']%2 == 1){
$arr['number_str'] = 'odd';
} else {
$arr['number_str'] = 'even';
}
}
foreach( $arr as $key => &$val ){
if(is_array($val)){
self::even_or_odd($val);
}
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.