Question

when using iterators in PHP you can use iterator_to_array function to kind of extract the array resulting of iterating. For example, let's say you have following ArrayObject:

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

As you see, its storage is a bi-dimensional array.

We can crete a FilterOperator to only accept its first item (I know it would be better with LimitIterator, it's just as an example purpose):

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

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

Now, if i do:

print_r(iterator_to_array($filter_iterator));

I get the array I could get if I manually loop through the operator:

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

But what now if I want to work with a RecursiveFilterIterator? Let's say I have:

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

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

As you see, this will accept only key 0 for each array contained in the parent array. And so it works if I recursive iterate over it:

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

Results in:

1
5
9

But, how could I get quickly the array array(array(1), array(5), array(9)) ?

If I do:

print_r(iterator_to_array($recursive_filter_iterator));

or

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

or

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

I get whole original array:

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

If I do:

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

I get just first item:

Array ( [0] => 9 )

If I do:

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

I get last item in my parent array but with key 0:

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

What I need is to get the array:

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

I know I can get it manually looping, but I want to know if there is a direct way, like in iterator_to_array for not recursive iterators. Sure there is something I don't understand about recursive iterators in PHP, but its documentation is really bad in this.

Thank you very much.

Was it helpful?

Solution

It is not entirely clear what you are really wanting to do, but the following takes a RecursiveArrayIterator (note: ArrayObject is not a recursive iterator) and uses iterator_to_array() to get the resulting array that you want.

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

OTHER TIPS

Do you need/want to use iterators? You could use php's built-in array_map() function which takes an array and a function and applies the specified function to each element in the array. So you could do:

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

The result will be:

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

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

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

I apologise if I have misunderstood your question.

OK. One easy way could be the following. It extends the ArrayIterator class and overrides the current() function to return the sliced array:

<?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));
?>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top