printSTL

printОбработка последовательностей

В качестве последовательности может быть использован любой контейнерный класс, а в пространстве имен std::views определены следующие генераторы:

Диапазон Описание
views::empty() пустая последовательность
views::single(x) одно значение
views::iota(a) последовательность [a,+)
views::iota(a,b) последовательность [a,b)
views::counted(first,n) n значений, начиная с first

Для обработки последовательностей можно использовать специальные варианты алгоритмов, объявленные в пространстве имен std::ranges. Их можно применять ко всему содержимому контейнера, не указывая begin и end.

#include <ranges>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
  vector<int> v{ 5, 10, 8, 3, 6, 12 };
  ranges::sort(v);
  for(auto x : views::iota(1,10)) {...}
  int a[100];
  for(auto x : views::counted(a,10)) {...}
}

С последовательностями можно выполнять следующие операции:

Операция Описание
views::take(n) взять первые n значений
views::take_while(fun) взять первые значения, удовлетворяющие fun
views::drop(n) пропустить первые n значений
views::drop_while(fun) пропустить первые значения, удовлетворяющие fun

Операции применяются в форме последовательность|операция1|операция2|… или операция(последовательность,параметры)

Для преобразования последовательности используются операции

Операция Описание
views::reverse в обратном порядке
views::transform(fun) выполнить fun над каждым элементом
views::filter(fun) оставить в последовательности только значения, удовлетворяющие fun
views::keys извлечь первое поле пары
views::values извлечь второе поле пары
views::elements<K> извлечь K-е поле кортежа
views::split(v) разделение на подпоследовательности по v
views::join соединение подпоследовательностей в одну

Для ввода данных можно использовать генератор ranges::istream_view<T>(istream)

#include <iostream>
#include <ranges>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
  vector<int> v;
  int n; cin>>n;
  ranges::copy(ranges::istream_view<int>(cin)|
    views::take(n),
    back_inserter(v));
  for(auto x:v|views::filter([](int x){ return x%2==0; })|
     views::transform([](auto x){return x*x;}))
  { cout<<x<<"\n"; }
}
  // вывести квадраты введенных чисел
  ranges::copy(ranges::istream_view<int>(cin)|
    views::transform([](auto x){return x*x;}),
    std::ostream_iterator<int>(cout, "\n"));

Альтернативный подход к обработке последовательностей предложен в библиотеке pipes

std::vector<int> v{ 5, 10, 8, 3, 6, 12 };
std::vector<int> r;
v>>=pipes::filter([](auto x){ return x%2 == 0; })
 >>=pipes::transform([](int x){ return x*x; }) 
 >>=pipes::push_back(r);

ranges основаны на "вытягивании", поскольку компоненты запрашивают следующее значение, то есть читают данные в ленивом режиме. pipes основаны на "выталкивании" и предназначены для отправки данных по мере их поступления в конечную точку через конвейер, то есть компоненты ждут следующего значения.

Оба набора классов имеют похожие компоненты, такие как преобразование и фильтр. Но pipes могут смешивать и разделять (fork) последовательности, а ranges могут обрабатывать бесконечные последовательности.

loading