Отфильтрованный (круговой) обход диапазона, начиная с итератора по исходной последовательности - PullRequest
0 голосов
/ 02 апреля 2020

Скажем, у вас есть контейнер и итератор для некоторого элемента этого контейнера. Требуется продвигать этот итератор по кругу, но с фильтром. Теперь создание отфильтрованного (кругового) представления последовательности является тривиальным, но как вы инициируете обход, когда все, что у вас есть, это итератор над оригиналом? Я думал о объединении двух диапазонов, например:

#include <iostream>

#include <range/v3/all.hpp>
using namespace ranges;

int main () {
    std::vector< int > xs{ -4, 1, 3, -4, 2, -3, 6, 7, 8, -9, -10 };

    auto iter = xs.begin ();
    std::advance (iter, 8);

    std::cout << *iter << std::endl;

    auto lhs = make_subrange (iter, xs.end ());
    auto rhs = make_subrange (xs.begin (), iter);

    auto is_pos = [](auto x) { return x >= 0; };
    auto rng = views::cycle (views::concat (lhs, rhs) | views::filter (is_pos));

    auto next = ++rng.begin ();
    std::cout << *next << std::endl;

    return 0;
}

Есть ли более простой подход?

1 Ответ

1 голос
/ 11 апреля 2020

Да, вместо объединения 2 поддиапазонов на iter, вы можете просто drop элементы до iter.

Таким образом, этот фрагмент

auto lhs = make_subrange (iter, xs.end ());
auto rhs = make_subrange (xs.begin (), iter);

auto rng = views::cycle (views::concat (lhs, rhs) | views::filter (is_pos));

становится

auto rng = xs | views::cycle
              | views::drop(distance(xs.begin(), iter))
              | views::filter(is_pos);

Обратите внимание, что, хотя это решение на проще , оно циклически перебирает все нефильтрованные элементы, и применяет предикат фильтра несколько раз. Ваше решение, вероятно, более эффективнее , чем это.

...