如何使用RecursiveIteratorIterator修改某些Array键

时间:2013-07-25 19:38:10

标签: php recursion iterator spl

我有一个多级数组。级别(子阵列)的数量是未知的。它可能只有两个,但也可能是5个。 我唯一知道的是 - 每个级别都有某些(已知)键。

让我们考虑以下示例:

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'键并创建“偶数”或“奇数”,等文本,结果应保存在自己的密钥下(例如number_str }}每个级别

所以修改后的数组应如下所示:

 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
    )

所以我尝试使用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);
    }
}

但它没有用。 所以我发现了一种“解决方法”。似乎这样做,我期望如果每个子数组是stdClass的对象

将原始Array(和所有子数组)转换为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);

现在看起来我希望得到结果,唯一的问题是,所有子级别现在都是stdClass的实例

在线代码 - > http://ideone.com/PIiZOX

问题有没有办法获得相同的结果,但没有json_decode / json_encode的噱头所以输出将是一个正常的数组?

P.S:我知道,有array_walk()但它不是一个选项

更新:我应该提一下,关于获得正确结果的问题。我知道,自定义recursiv函数(也许array_walk_recursive())可以解决问题。 它更多地关于SPL RecursiveIterators 作为可能的解决方案。我只是想知道自己,为什么它与strClass es一起工作,为什么不使用常规数组。

来自obeve的示例数组不是真正的用例。正如您可能猜到的那样,实际的用例是来自DB的数据的数组(有时超过600行)。其中一些有子阵列。我唯一知道的是应该修改的键(通过给定的规则)。 效果是主要标准

3 个答案:

答案 0 :(得分:1)

尝试使用自定义递归函数:

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);

看到它在这里工作:http://codepad.viper-7.com/vBc42b

答案 1 :(得分:1)

我认为不需要使用RecursiveArrayIterator,简单的递归函数就足够了。 希望这会有所帮助:

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);

答案 2 :(得分:1)

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);
            }
        }
    }
}