MySQL Java JavaScript PHP Python HTML-CSS C-sharp C++ Go

Reprezentări - Filtrare

O reprezentare sau view este un interval ușor care face referire la elemente, dar nu le deține. Reprezentările sunt, de obicei, bazate pe alte intervale și oferă o metodă specifică de a lucra cu acest interval, cum ar fi transformarea sau filtrarea. Există un container care stochează efectiv elementele și o reprezentare care face referire la aceste elemente.

Reprezentările sunt mai eficiente din punct de vedere al performanței decât intervalele standard bazate pe iteratori, deoarece reprezentarea nu deține elementele la care face referire, astfel încât nu trebuie să facă o copie a acestora. Prin urmare, se pot crea reprezentări fără pierderi de performanță.

Pentru a crea reprezentări se folosesc adaptatori de intervale (range adapter). Există două moduri de a defini o reprezentare:

  • Utilizarea constructorului de reprezentare std::ranges::xxx_view, unde xxx este numele reprezentării:
auto view = std::ranges::xxx_view{ range, args } // constructorul de reprezentare

Primul parametru este containerul pentru care se creează reprezentarea, iar al doilea parametru definește funcția aplicată pentru crearea reprezentării.

  • Utilizarea operatorului | pe container și funcția std::views::xxx, unde xxx este numele reprezentării:
auto view = range | std::views::xxx(args)

Aici, range este și el un container, iar funcția std::views::xxx() primește un parametru care definește funcția utilizată pentru crearea reprezentării.

Filtrare

Pentru filtrare se folosește reprezentarea std::ranges::filter_view. Al doilea parametru al constructorului reprezintă condiția – o funcție care primește un obiect și returnează un rezultat de tip bool: true dacă obiectul satisface condiția și false dacă nu o satisface.

De exemplu, să filtrăm elementele unui vector:

#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();
    }
}

În acest exemplu, vectorul stochează obiecte de tip Person, fiecare având un nume și o vârstă. Folosind std::ranges::filter_view, obținem toate obiectele Person din vectorul people care au vârsta mai mare de 33:

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

Funcția ageMoreThan33() este folosită pentru a verifica dacă vârsta este mai mare de 33. Se putea folosi și un lambda în locul acestei funcții. Rezultatul filtrării va fi un interval de obiecte Person care îndeplinesc această condiție. Programul va afișa:

Tom     38
Bob     42
Alice   34

Aceleași rezultate se pot obține folosind un lambda pentru condiție:

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 = std::ranges::filter_view{people, ageMoreThan33};
 
for (const auto& person : filter_view)
{
    person.print();
}

Al doilea mod de a crea o reprezentare pentru filtrare folosește funcția std::views::filter(), la care se transmite o funcție de filtrare.

#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();
    }
}

Pentru a crea reprezentarea pentru filtrare, folosim operatorul |, unde operanzii sunt containerul de date și funcția std::views::filter:

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

Rezultatul va fi același ca în cazul folosirii constructorului de reprezentare.