ardggy's blog

Esc - Meta - Alt - Ctrl - Shift

イテレータを合流させる

ソート済みの2つのイテレータを混ぜ合わせて直列にできないだろうか、という動機

<?php
declare(strict_types=1);

$iter = confluence(odds(), evens(), fn($x, $y) => $x <=> $y);
assert([0,1,2,3,4,5,6,7,8,9] === iterator_to_array(new LimitIterator($iter, 0, 10), $use_keys = false));

function confluence(Iterator $it1, Iterator $it2, Callable $compare): Iterator {
  while ($it1->valid() && $it2->valid()) {
    $v1 = $v1 ?? $it1->current();
    $v2 = $v2 ?? $it2->current();

    // どちらのイテレータからもらうかの選択
    // 改善の余地あり
    if ($compare($v1, $v2) < 0) {
      yield $v1;
      $it1->next();
      $v1 = $it1->current();
    } else {
      yield $v2;
      $it2->next();
      $v2 = $it2->current();
  }
  for ( ; $it1->valid(); $it1->next()) {
    yield $it1->current();
  }
  for ( ; $it2->valid(); $it2->next()) {
    yield $it2->current();
  }
}

function odds(): Iterator {
  for ($x = 1; 1; $x += 2) {
    yield $x;
  }
}

function evens(): Iterator {
  for ($x = 0; 1; $x += 2) {
    yield $x;
  }
}