PHP中单个循环中的多个生成器

问题描述 投票:8回答:5

我需要编写一个简单的脚本来加载来自多个文件的数据并以某种方式合并它。但是,鉴于文件可能非常庞大,我想部分加载数据。为此,我决定使用yield。根据示例,我发现我可以使用以下构造用于单个发电机:

$generator = $someClass->load(); //load method uses yield so it returns generator object
foreach($generator as $i) {
  // do something
}

但是,如果我想一次使用两台发电机怎么办?

$generatorA = $someClass1->load(); //load method uses yield so it returns generator object
$generatorB = $someClass2->load(); //load method uses yield so it returns generator object
foreach($generatorA as $i) {
  // how can I access to resultSet from generatorB here?
}
php generator yield
5个回答
15
投票

Generators in PHP实施Iterator interface,所以你可以合并/组合多个Generators,就像你可以结合多个Iterators。

如果你想一个接一个地迭代两个生成器(合并A + B),那么你可以使用AppendIterator

$aAndB = new AppendIterator();
$aAndB->append($generatorA);
$aAndB->append($generatorB);

foreach ($aAndB as $i) {
    ...

如果你想一次迭代两个生成器,你可以使用MultipleIterator

$both = new MultipleIterator();
$both->attachIterator($generatorA);
$both->attachIterator($generatorB);

foreach ($both as list($valueA, $valueB)) {
    ...

这两个包括的例子。示例和警告也在我的博客文章中:

否则我不明白你一直在问什么。如果你能澄清一下,我应该能给你更多指示。


0
投票

虽然AppendIteratorIterators工作,但它有一些问题。

首先,需要构造一个新对象而不是仅仅调用一个函数并不是那么好。更不错的是你需要改变AppendIterator,因为你不能在它的构造函数中提供内部迭代器。

其次AppendIterator只接受Iterator实例,所以如果你有Traversable,如IteratorAggregate,你运气不好。同样的故事,其他iterable不是Iterator,如array

这个PHP 7.1+功能结合了两个iterable

/**
 * array_merge clone for iterables using lazy evaluation
 *
 * As with array_merge, numeric elements with keys are assigned a fresh key,
 * starting with key 0. Unlike array_merge, elements with duplicate non-numeric
 * keys are kept in the Generator. Beware that when converting the Generator
 * to an array with a function such as iterator_to_array, these duplicates will
 * be dropped, resulting in identical behaviour as array_merge.
 *
 *
 * @param iterable ...$iterables
 * @return Generator
 */
function iterable_merge( iterable ...$iterables ): Generator {
    $numericIndex = 0;

    foreach ( $iterables as $iterable ) {
        foreach ( $iterable as $key => $value ) {
            yield is_int( $key ) ? $numericIndex++ : $key => $value;
        }
    }
}

用法示例:

foreach ( iterable_merge( $iterator1, $iterator2, $someArray ) as $k => $v ) {}

这个功能是small library for working with iterable的一部分,它也经过了广泛的测试。


-1
投票

我相信你可以先合并两个数组,然后在相同的foreach中使用它

喜欢:

$generatorA = $someClass1->load(); //load method uses yield so it returns generator object
$generatorB = $someClass2->load(); //load method uses yield so it returns generator object

$result = array_merge($generatorA, $generatorB);
foreach($result as $i) {
  //use as you want
}

详细信息:Array_merge


-1
投票

就像是:

$generatorA = $someClass1->load(); //load method uses yield so it returns generator object
$generatorB = $someClass2->load(); //load method uses yield so it returns generator object

$flag = true;
$i = 0;
while($flag === false) {

 if ($i >= count($generatorA) || $i >= count($generatorB)) {
      $flag = true;
 }

 // Access both generators
 $genA = $generatorA[$i];
 $genB = $generatorB[$i];

$i++;
}

-1
投票

试试这个:

<?php
foreach($generatorA as $key=>$i) {
    $A=$i;//value from $generatorA
    $B=$generatorB[$key];//value from $generatorB
}
© www.soinside.com 2019 - 2024. All rights reserved.