2012-02-02 2 views
5

при использовании итераторов в PHP вы можете использовать функцию iterator_to_array для получения извлечения массива, полученного в результате итерации. Например, предположим, что у вас есть следующие ArrayObject:вид iterator_to_array для рекурсивного итератора для получения двумерного массива

$array_object = new ArrayObject(array(
    array('1', '2', '3', '4'), 
    array('5', '6', '7', '8'), 
    array('9', '10', '11', '12'), 
)); 

Как вы видите, его хранение является двумерная матрица.

Мы можем крит FilterOperator только принять его первый пункт (я знаю, что было бы лучше с LimitIterator, это просто в качестве примера цели):

class myFilterIterator extends FilterIterator 
{ 
    public function accept() 
    { 
     return ($this->key() === 0); 
    } 
} 

$filter_iterator = new myFilterIterator(new ArrayIterator($array_object)); 

Теперь, если я делаю:

print_r(iterator_to_array($filter_iterator)); 

Я получаю массив я мог бы получить, если я вручную цикл через оператора:

Array ([0] => Array ([0] => 1 [1] => 2 [2] => 3 [3] => 4)) 

Но что теперь, если я хочу работать с RecursiveFilterIterator? Предположим, у меня есть:

class myRecursiveFilterIterator extends RecursiveFilterIterator 
{ 
    public function accept() 
    { 
     return ($this->hasChildren() || $this->key() === 0); 
    } 
} 

$recursive_filter_iterator = new myRecursiveFilterIterator(new RecursiveArrayIterator($array_object)); 

Как вы видите, это будет принимать только ключ 0 для каждого массива, содержащегося в родительском массиве. И поэтому он работает, если я рекурсивной итерации над ним:

foreach (new RecursiveIteratorIterator($recursive_filter_iterator) as $value) { 
    print_r($value); 
    echo '<br />'; 
} 

Результаты в:

1 
5 
9 

Но, как я мог быстро получить массив array(array(1), array(5), array(9))?

Если я:

print_r(iterator_to_array($recursive_filter_iterator)); 

или

print_r(iterator_to_array($recursive_filter_iterator->getInnerIterator())); 

или

$it = new RecursiveIteratorIterator($recursive_filter_iterator); 
print_r(iterator_to_array($it->getInnerIterator())); 

я получаю весь исходный массив:

Array ([0] => Array ([0] => 1 [1] => 2 [2] => 3 [3] => 4) [1] => Array ([0] => 5 [1] => 6 [2] => 7 [3] => 8) [2] => Array ([0] => 9 [1] => 10 [2] => 11 [3] => 12)) 

Если я:

print_r(iterator_to_array(new RecursiveIteratorIterator($recursive_filter_iterator))); 

Я получаю только первый пункт:

Array ([0] => 9) 

Если я:

print_r(iterator_to_array(new RecursiveIteratorIterator($recursive_filter_iterator->getInnerIterator()))); 

я получаю последний элемент в моем родительском массиве, но с ключом 0:

Array ([0] => 9 [1] => 10 [2] => 11 [3] => 12) 

Что мне нужно, чтобы получить массив:

Array ([0] => Array ([0] => 1) [1] => Array ([0] => 5) [2] => Array ([0] => 9)) 

Я знаю, что я могу получить его вручную зацикливание, но я хочу знать, если есть прямой путь, как и в iterator_to_array для не рекурсивных итераторов. Конечно, есть что-то, что я не понимаю о рекурсивных итераторах в PHP, но его документация в этом плохо.

Большое спасибо.

+0

* «его документация очень плохая» * - любая обратная связь по этой теме приветствуется, пришлите мне электронное письмо (мое имя пользователя на SO, @ php.net). – salathe

ответ

3

Это не совсем понятно, что вы на самом деле хотите сделать, но следующий берет RecursiveArrayIterator (примечание: ArrayObject является а не рекурсивный итератор) и использует iterator_to_array(), чтобы получить полученный массив, который вы хотите.

class FirstOnlyRecursiveArrayIterator extends ParentIterator { 
    public function __construct(RecursiveArrayIterator $it) { 
     parent::__construct($it); 
    } 
    public function current() { 
     $children = parent::current(); 
     return array_slice($children, 0, 1); 
    } 
} 

$array_it = new RecursiveArrayIterator(array(
    array('1', '2', '3', '4'), 
    array('5', '6', '7', '8'), 
    array('9', '10', '11', '12'), 
)); 

$filter_iterator = new RecursiveIteratorIterator(
    new FirstOnlyRecursiveArrayIterator($array_it), 
    RecursiveIteratorIterator::SELF_FIRST); 
print_r(iterator_to_array($filter_iterator)); 
+0

Хорошо, спасибо @salathe. Это действительно работает.Но я думаю, что это довольно странно, или, по крайней мере, я этого не понимаю. Документация PHP говорит, что 'ParentIterator'' 'FilterIterator '' расширен, чтобы отображать только элементы, у которых есть дети. Поэтому я думаю, что его метод 'accept()' определяет только его дочерний элемент. Переписывать 'current()' метод для фильтрации, а не 'accept()' Я думаю, что это не очень чисто. Кроме того, мой пример должен работать, потому что я проверяю также, если у текущего есть дети, но это не так. –

0

Вам нужны/нужны итераторы? Вы можете использовать встроенную функцию array_map() php, которая принимает массив и функцию и применяет указанную функцию к каждому элементу массива. Таким образом, вы можете сделать:

<?php 
function get_first($foo) 
{ 
    return array_slice($foo, 0, 1); //slice the array right after the first element 
} 

$array_object = new ArrayObject(array(
    array('1', '2', '3', '4'), 
    array('5', '6', '7', '8'), 
    array('9', '10', '11', '12'), 
)); 

$new_array = array_map("get_first", $array_object->getArrayCopy()); 
print_r($new_array); 
?> 

Результат будет:

Array 
(
    [0] => Array 
     (
      [0] => 1 
     ) 

    [1] => Array 
     (
      [0] => 5 
     ) 

    [2] => Array 
     (
      [0] => 9 
     ) 
) 

Я прошу прощения, если я неправильно понял ваш вопрос.

+0

Да, я хотел бы добиться этого, но используя итераторы :) Спасибо, @csOlar –

0

ОК. Одним из простых способов может быть следующее. Он расширяет класс ArrayIterator и переопределяет функцию тока(), чтобы вернуть нарезанную массив:

<?php 
class FirstOnlyIterator extends ArrayIterator 
{ 
    public function current() 
    { 
      $next = parent::current(); 
      return array_slice($next, 0, 1); 
    } 
} 

$array_object = new ArrayObject(array(
    array('1', '2', '3', '4'), 
    array('5', '6', '7', '8'), 
    array('9', '10', '11', '12'), 
)); 

$iterator = new FirstOnlyIterator($array_object); 

print_r(iterator_to_array($iterator)); 
?> 
+0

Эй, да, я знаю, что есть простые способы добиться того, чего я хочу, но я хотел бы получить это, используя рекурсивные итераторы , В любом случае, спасибо. –