Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access first element in iterator?

Tags:

I'm using a PHP framework that returns SQL results as iteratable objects. Problem is I have a SQL query that that returns one row and I don't want to have to create a foreach-loop to get at the first - and only - element.

So how do I do it?

These don't work:

$obj->item(0)->propName;
$obj->next()->propName;
$obj[0]->propName;

Any ideas?

like image 463
neubert Avatar asked Jan 22 '13 06:01

neubert


People also ask

How do you get the first element of a collection?

List interface provides a get() method to get the element at particular index. You can specify index as 0 to get the first element of the List.

Does iterator next return the first element?

This has nothing to do with the position of the iterator. next() picks out and remembers the element at the pointer, then advances the pointer, then returns the remembered element. You're overthinking it. next() returns the next element in the sequence, starting with the first element.

Which method is used to get the first element from a?

The firstElement() method of Java Vector class is used to get the first element ( at index 0 ) of the vector which is in use.

Which function moves the iterator to first element of the array?

rewind() Moves the iterator to the first element in the array.


2 Answers

Assuming by "iterable", you mean that the object implements the Iterator interface, you can use $obj->current() to retrieve the current element, so $obj->current()->propName is probably what you want.

If the iterator pointer has been moved (for example, if it was used in a foreach, which doesn't reset the pointer), then you can call $obj->rewind() to set the pointer back to the first element before you call $obj->current().

like image 78
AgentConundrum Avatar answered Sep 21 '22 14:09

AgentConundrum


There are only two class interfaces that can be traversed: Iterator and IteratorAggregate (any other must implement one of them).


Iterator

First element of Iterator can be obtained as follows:

$iterator->rewind();
if (!$iterator->valid()) {
    throw new Exception('There is no any element!');
}
$firstElement = $iterator->current();

If you are sure:

  • the $iterator was never been traversed by foreach, or if it was but the loop was never stopped with break or return (since PHP 7 this point is irrelevant because foreach does not affect pointer)
  • there was never called $iterator->next();

you can omit the $iterator->rewind(); from the previous example.

If you are sure the count of elements in $iterator is not zero, you can even omit the condition block testing $iterator->valid().

So if these previous conditions are preserved then what you need is just:

$firstElement = $iterator->current();

IteratorAggregate

IteratorAggergate is actually just an envelope for an Iterator or another IteratorAggregate. Logically that means there is an Iterator at the end.

If you know how many levels deep the Iterator is, just grab it and use as in the very first example:

$iterator = $iteratorAggregate->getIterator();

But if you don't now the deepness, you may use a solution which works also for an Iterator:

$array = iterator_to_array($iteratorAggregate);
// $array is an ordinary array now
if (count($array) === 0) {
    throw new Exception('There is no any element!');
}
$firstElement = reset($array);

Unfortunately in case of biig array this is a little overkill because copy of all elements must be created despite we need just one. Besides if the Iterator is an infinite Generator you will run out of memory.

There is one solution that works:

while ($iterator instanceof \IteratorAggregate) {
    $iterator = $iterator->getIterator();
}
// $iterator now contains instance of Iterator

I made a simple benchmark for an array of 10000 members and this solution was almost 6 times faster.

So, the universal solution which will work for all cases is:

while ($iterator instanceof \IteratorAggregate) {
    $iterator = $iterator->getIterator();
}
$iterator->rewind();
if (!$iterator->valid()) {
    throw new Exception('There is no any element!');
}
$firstElement = $iterator->current();

LLAP

like image 45
hejdav Avatar answered Sep 22 '22 14:09

hejdav