【问题标题】:How do I use a recursive array iterator to process a multidimensional array?如何使用递归数组迭代器来处理多维数组?
【发布时间】:2011-04-19 06:30:54
【问题描述】:

我正在尝试让这样的东西工作:

function posts_formatter (&$posts){
    foreach ($posts as $k => $v){

        if (is_array($v)){

            posts_formatter($v);

        }else{

            switch (strtolower($k)){

                # make email addresses lowercase
                case (strpos($k, 'email') !== FALSE):
                    $posts[$k] = strtolower($v);
                    break;

                # make postcodes uppercase
                case (strpos($k, 'postcode') !== FALSE):
                    $posts[$k] = strtoupper($v);
                    break;

                # capitalize certain things
                case (strpos($k, 'line1') !== FALSE):
                case (strpos($k, 'line2') !== FALSE):
                case (strpos($k, 'line3') !== FALSE):
                case (strpos($k, 'forename') !== FALSE):
                case (strpos($k, 'surname') !== FALSE):
                    $posts[$k] = capitalize($v);
                    break;
            }

        }
    }
}

它将正确地遍历数组并格式化值,但我无法让它返回它们。我已经尝试从函数声明中删除 & 并在最后添加一个 return 但它不会做任何事情。

此外,我在想也许使用RecursiveArrayIterator 可能是要走的路。然而,尽管我面前有一本书,其中有一章是关于 SPL 迭代器的,但它的示例对于实现我想要实现的目标毫无用处。我将如何实施?

编辑:

array (
  'user' => 
  array (
    'title' => 'Mr.',
    'forename' => 'lowercase',
    'surname' => 'name',
    'businessName' => 'some dude',
    'telephone' => '07545464646',
    'postcode' => 'wa1 6nj',
    'line1' => 'blergh road',
    'line2' => 'randomLY cApitaLIzed wOrds',
    'line3' => '',
  ),
  'email' => 'CAPITALIZED@BLERGH.com',
  'address' => 
  array (
    'postcode' => 'ab1 1ba',
    'line1' => 'test road',
    'line2' => 'testville',
    'line3' => 'testshire',
  ),
  'date' => '2010-09-30'
)

【问题讨论】:

  • 愿意提供var_export 示例数组吗?
  • 嗯,数组可以是任何多维(或基本)数组,这就是重点。所有函数需要做的就是寻找那些特定的键,它们可能存在也可能不存在于数组中并格式化它们的值。问题是让它将它们输出回脚本。
  • 我问是因为为了写一个例子,我想使用你的实际数据而不是想出一个虚拟数组。这只是为了让为您编写代码变得不那么乏味。
  • 您的 switch/case 构造无法按照您可能想要的方式工作。你所拥有的就像if ( strtolower($k) == (strpos($k, 'email')!==FALSE) )
  • 很公平!我认为您需要它来更好地理解问题。

标签: php recursion iterator multidimensional-array


【解决方案1】:

好的,这里有一个快速的东西供你弄清楚:

$data = array(
    'title'    => 'how to work with iterators',
    'posts' => array(
        array(
        'title'  => 'introduction to iterators',
        'email'  => 'JohnDoe@example.com'
     ), array(
        'title'  => 'extending iterators',
        'email'  => 'JaneDoe@example.com'
     )
));

主要思想是影响Iterator 如何返回current 元素。迭代器是可堆叠的,因此您应该使用RecursiveArrayIterator 并将其包装到RecursiveIteratorIterator 中。要实现自定义功能,您可以继承RecursiveIteratorIterator(如下所示)或使用额外的迭代器来装饰RecursiveIteratorIterator

class PostFormatter extends RecursiveIteratorIterator
{
    public function current()
    {
        $current = parent::current();
        switch($this->key()) {
            case 'email':
                $current = strtolower($current);
                break;
            case 'title':
                $current = ucwords($current);
                break;
            default:
                break;
        }
        return $current;
    }
}

然后你只需在迭代器上 foreach

$it = new PostFormatter(new RecursiveArrayIterator($data));
foreach($it as $key => $post) {
    echo "$key: $post", PHP_EOL;
}

得到

title: How To Work With Iterators
title: Introduction To Iterators
email: johndoe@example.com
title: Extending Iterators
email: janedoe@example.com

您可以尝试使用iterator_to_arrayiterator_apply 函数来取回数组。但是,要将值重新应用于原始数组结构,您不需要迭代器:

array_walk_recursive($data, function(&$val, $key) {
    switch($key) {
        case 'title': $val = ucwords($val); break;
        case 'email': $val = strtolower($val); break;
        default: break;
    }
});
print_r($data);

注意:使用 PHP 时用函数名交换 Lambda

【讨论】:

  • 感谢您的帮助戈登。再快速问一下 - 我如何修改它以返回原始数组结构完整的已处理数组?
  • 感谢您的详细解释。
  • @bcmcfc 不客气。我不得不删除 iterator_to_array 代码,因为它不会将更改应用于内部数组。我相信你可以以某种方式做到这一点,但现在我不能摆弄它(时间限制)。对不起。
猜你喜欢
  • 2013-11-11
  • 2020-03-21
  • 1970-01-01
  • 2014-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-28
  • 2017-11-28
相关资源
最近更新 更多