SPL InfiniteIterator не работает со следующими или предыдущими - PullRequest
0 голосов
/ 19 февраля 2019

Я хотел бы над массивом бесконечно, как круговой массив.

У меня есть следующая настройка, использующая InfiniteIterator 1 , которая перебирает $players бесконечно.Но на самом деле, я хочу знать следующего игрока и предыдущего игрока из этого цикла, как показано ниже

$players = new InfiniteIterator(new ArrayIterator(['Shobi', 'Jomit']));

foreach ($players as $player) {
    echo $player; // current player name comes properly infinetly
    echo next($players); // next player should come
    echo current($players); // current player should come
    echo prev($players); //previous player should come
}

, но next() и prev() всегда возвращают ноль

Из документа яя вижу, что эти методы возвращают void, но есть ли способ, как я могу расширить InfiniteIterator и добиться этого необходимого механизма?

Как заставить next() и prev() работать с InfiniteIterator?

Редактировать current() возвращает текущий элемент (это означает, что он работает правильно в логике)

Ответы [ 3 ]

0 голосов
/ 20 февраля 2019

Вы можете сойти с ума с PHP-итераторами и сделать что-то вроде следующего:

$array = ['Shobi', 'Jomit', 'John', 'Jane', 'Smith'];

// Use NoRewindIterator to prevent MultipleIterator rewinding.
$players1 = new NoRewindIterator(new InfiniteIterator(new ArrayIterator($array)));
// Go to the end of array, i.e. set prev player.
for ($i = 0, $size = count($array); $i < $size - 1; $i++) {
    $players1->next();
}

$players2 = new InfiniteIterator(new ArrayIterator($array));
$players2->next();

// Use NoRewindIterator to prevent MultipleIterator rewinding.
$players3 = new NoRewindIterator(new InfiniteIterator(new ArrayIterator($array)));
$players3->next(); // Go to the second player, i.e. next player

// MultipleIterator will traverse three iterators at once.
// Since the pointer in each iterator differs in one position, we will have prev, curr and next.
$players = new MultipleIterator(MultipleIterator::MIT_NEED_ALL|MultipleIterator::MIT_KEYS_ASSOC);
$players->attachIterator($players1, 'prev');
$players->attachIterator($players2, 'curr');
$players->attachIterator($players3, 'next');

$i = 0;
foreach ($players as $player) {
    print_r($player);

    if (++$i >= 10) {
        break;
    }
}

Пожалуйста, посмотрите демо .

0 голосов
/ 27 февраля 2019

Размещение ответа, который я наконец-то придумал.

В моем случае бесконечный итератор не работал.Тем более, что я не смог переместить указатель назад с помощью функции prev().Поэтому я реализовал интерфейс Iterator и переопределил методы next и prev соответственно.

Так, чтобы при вызове next() и в конце массива, он перемотает указатель на начало, аналогично, если вызывается prev() и указатель уже находится в начале, он переместит указатель в конец внутреннего массива.Это сработало для меня отлично.

Соответствующий код

<?php

class CircularIterator implements Iterator
{
    ...
    ...
    public function next()
    {
        next($this->entries);
        if (!$this->current()) {
            $this->rewind();
        }
    }

    public function prev()
    {
        prev($this->entries);
        if (!$this->current()) {
            $this->end();
        }
    }
  ....
  ....
}

полная реализация и пример кода - Ссылка

0 голосов
/ 19 февраля 2019

Если вместо использования итераторов вы можете просто использовать массив и указатель на «текущую» запись, а затем использовать цикл while(true), который будет продолжать работать (вы всегда можете добавить break, чтобы остановить его длятестирование или какое-то условие).Различные части логики проверяют, является ли текущий игрок последним, то есть следующим является начальный, или же это первый элемент, а предыдущий является конечным.Также приращение сбрасывается, как только оно достигает конца и начинается снова ...

$players = ['Shobi', 'Jomit'];
$playerKey = 0;
$playerCount = count($players);
while(true) {
    echo $players[($playerKey+1)%$playerCount].PHP_EOL; // next player
    echo $players[$playerKey].PHP_EOL; // current player
    echo $players[($playerKey>0)?$playerKey-1:$playerCount-1].PHP_EOL; //previous player
    $playerKey = ( $playerKey+1 == $playerCount )?0:$playerKey+1;
}
...