Представления. Фильтрация

Последнее обновление: 31.03.2023

Представление или view представляет легковесный диапазон, которое ссылается на элементы, которыми оно не владеет. Представление обычно основано на другом диапазоне и обеспечивает определенный способ работы с этим дипазоном, например, преобразование или фильтрация. То есть есть некоторый контейнер, который непосредственно хранит элементы, и есть представление, которое ссылается на эти элементы. При этом представления более эффективны в плане производительности, чем стандартные диапазоны, основанные на итераторах. Это связано с тем, что представление не владеет элементами, на которые оно ссылается, поэтому ему не нужно делать копию. Поэтому можно создавать представления без потери производительности.

Для создания представлений применяются адаптеры диапазонов (range adapter). Есть два способа определения представления.

  • Применение конструктора представления std::ranges::xxx_view, где xxx - название представления

    auto view = std::ranges::xxx_view{ range, args } // конструктор представления
    

    Первый параметр - контейнер, для которого создается представления, второй параметр определяет функцию, применяемую для создания представления

  • Применение операции | к контейнеру и функции std::views::xxx, где xxx - название представления

    auto view = range | std::views::xxx(args)
    

    Здесь range также представляет контейнер, а функция std::views::xxx() в качестве параметра принимает функцию, которая применяется для создания представления

Рассмотрим на примере самой распространенной операции - фильтрации.

Фильтрация

Для фильтрации применяется представление std::ranges::filter_view. В качестве второго параметра конструктор представления принимает условие - функцию, которая принимает некоторый объект и возвращает значение типа bool - true, если объект соответствует условию, и false, если не соответствует.

Например, отфильтруем элементы вектора

#include <iostream>
#include <vector>
#include <ranges>

class Person
{
public:
    Person(std::string name, unsigned age): name{name}, age{age}{}
    std::string getName() const {return name;}
    unsigned getAge() const {return age;}
    void print() const  
    {
        std::cout << name <<"\t" << age << std::endl;
    }
private:
    std::string name;
    unsigned age;
};
bool ageMoreThan33(const Person& person) 
{ 
    return person.getAge() > 33; 
}
int main()
{
    std::vector<Person> people 
    {
        Person{"Tom", 38}, Person{"Kate", 31}, Person{"Bob", 42}, 
        Person{"Alice", 34}, Person{"Sam", 25}
    };
    auto filter_view = std::ranges::filter_view{people, ageMoreThan33};

    for(const auto& person: filter_view)
    {
        person.print();
    }
}

Здесь вектор хранит объекты типа Person, для каждого из которых устанавливается имя и возраст. И в данном случае из вектора получаем все объекты Person, возраст которых больше 33:

auto filter_view = std::ranges::filter_view{people, ageMoreThan33};

Условие вынесено в отдельную функцию ageMoreThan33(), которая возвращает true, если возраст больше 33. Также можно было бы определить условие в виде лямбда-выражения.

В результате вызова конструктора std::ranges::filter_view мы получим представление с объектами Person, которые соотвествуют условию. Полученное представление можно также перебрать с помощью цикла for и получить каждый его элемент (в данном случае объекты Person). Консольный вывод программы:

Tom     38
Bob     42
Alice   34

Подобным образом можно было бы передать вместо внешней функции лямбда-выражение:

std::vector people 
{
    Person{"Tom", 38}, Person{"Kate", 31}, Person{"Bob", 42}, 
    Person{"Alice", 34}, Person{"Sam", 25}
};
auto ageMoreThan33 = [](const Person& p){return p.getAge() > 33;};
auto filter_view = std::ranges::filter_view{people, ageMoreThan33};

for(const auto& person: filter_view)
{
    person.print();
}

Второй способ создания представления фильтрации представление применение функции std::views::filter(), в которую передается функция филтрации

#include <iostream>
#include <vector>
#include <ranges>

class Person
{
public:
    Person(std::string name, unsigned age): name{name}, age{age}{}
    std::string getName() const {return name;}
    unsigned getAge() const {return age;}
    void print() const  
    {
        std::cout << name <<"\t" << age << std::endl;
    }
private:
    std::string name;
    unsigned age;
}; 
int main()
{
    std::vector<Person> people 
    {
        Person{"Tom", 38}, Person{"Kate", 31}, Person{"Bob", 42}, 
        Person{"Alice", 34}, Person{"Sam", 25}
    };
    auto ageMoreThan33 = [](const Person& p){return p.getAge() > 33;};
    auto filter_view = people | std::views::filter(ageMoreThan33);

    for(const auto& person: filter_view)
    {
        person.print();
    }
}

Для создания представления фильтрации используем операцию |, в которой операндами выступают контейнер данных и функция std::views::filter:

auto filter_view = people | std::views::filter(ageMoreThan33);

Результат будет тем же самым, что в случае использования конструктора представления.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850