如何访问迭代器中的第一个元素?迭 代迭代器聚合器

2022-08-30 19:47:59

我正在使用一个PHP框架,它将SQL结果作为可迭代对象返回。问题是我有一个返回一行的SQL查询,我不想创建一个-循环来获取第一个 - 也是唯一一个 - 元素。foreach

那么我该怎么做呢?

这些不起作用:

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

有什么想法吗?


答案 1

假设“可迭代”,你的意思是对象实现了迭代器接口,你可以用它来检索当前元素,所以可能是你想要的。$obj->current()$obj->current()->propName

如果迭代器指针已被移动(例如,如果它用于 不重置指针的 ,则可以在调用 之前调用以将指针设置回第一个元素。foreach$obj->rewind()$obj->current()


答案 2

只有个类接口可以遍历:迭代器迭代器聚合(任何其他接口都必须实现其中之一)。


迭 代

迭代器的第一个元素可以得到如下:

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

如果您确定:

  • 从未被 遍历过,或者如果是,但循环从未停止过 或 (因为 PHP 7 这一点无关紧要,因为 foreach 不会影响指针$iteratorforeachbreakreturn)
  • 从来没有叫过$iterator->next();

您可以省略上一个示例中的 。$iterator->rewind();

如果您确定 中的元素计数为零,您甚至可以省略 条件 块测试 。$iterator$iterator->valid()

因此,如果保留了这些先前的条件,那么您只需要:

$firstElement = $iterator->current();

迭代器聚合器

IteratorAggergate实际上只是一个迭代器或另一个迭代器Aggregate的信封。从逻辑上讲,这意味着最后有一个迭代器。

如果您知道迭代器有多深,只需抓住它并使用,如第一个示例所示:

$iterator = $iteratorAggregate->getIterator();

但是,如果您不知道深度,则可以使用也适用于迭代器的解决方案:

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

不幸的是,在biig数组的情况下,这有点过分了,因为尽管我们只需要一个,但必须创建所有元素的副本。此外,如果迭代器是无限生成器,您将耗尽内存。

有一种解决方案有效:

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

我为一个包含 10000 个成员的数组做了一个简单的基准测试,这个解决方案快了 6 倍。

因此,适用于所有情况的通用解决方案是:

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

拉帕普


推荐