```C++
int main() {
auto even = [](const auto& el) { return !(el.id() % 2); };
std::vector vec {Foo{1}, Foo{2}, Foo{3}, Foo{4}};
std::cout << "Start algorithm\n";
for (const auto& foo : vec
| std::views::filter(even)
| std::views::drop_while([](const auto& el){ return el.id() < 4; })) {
std::cout << "foo: " << foo << '\n';
}
}
```
We don't make any copy!
```C++
C'tor id: 1
C'tor id: 2
C'tor id: 3
C'tor id: 4
Copy C'tor id: 1
Copy C'tor id: 2
Copy C'tor id: 3
Copy C'tor id: 4
D'tor id:4
D'tor id:3
D'tor id:2
D'tor id:1
Start algorithm
foo: 4
D'tor id:1
D'tor id:2
D'tor id:3
D'tor id:4
```
___
## View (2)
This is also usefull to create `range loop` which iterate reversed:
```C++
int main() {
std::vector
students{{.index_ = 123456, .name_ = "Jordan", .average_ = 4.53},
{.index_ = 654321, .name_ = "Michael", .average_ = 4.51},
{.index_ = 246892, .name_ = "John", .average_ = 4.56},
{.index_ = 743561, .name_ = "Jane", .average_ = 4.44},
{.index_ = 811111, .name_ = "Anna", .average_ = 4.46}};
std::ranges::sort(students, {}, &Student::average_);
for (const auto& [index, name, average] : std::views::reverse(students)) {
std::cout << "student: " << name << " | index: " << index << " | avergae: " << average << '\n';
}
/*
student: John | index: 246892 | avergae: 4.56
student: Jordan | index: 123456 | avergae: 4.53
student: Michael | index: 654321 | avergae: 4.51
student: Anna | index: 811111 | avergae: 4.46
student: Jane | index: 743561 | avergae: 4.44
*/
}
```
___
## View (3)
We can also create `range loop` which iterates only through the first/last `k` elements:
```C++
int main() {
std::vector students{{.index_ = 123456, .name_ = "Jordan", .average_ = 4.53},
{.index_ = 654321, .name_ = "Michael", .average_ = 4.51},
{.index_ = 246892, .name_ = "John", .average_ = 4.56},
{.index_ = 743561, .name_ = "Jane", .average_ = 4.44},
{.index_ = 811111, .name_ = "Anna", .average_ = 4.46}};
std::ranges::sort(students, {}, &Student::average_);
for (const auto& [index, name, average] : std::views::reverse(students) | std::views::drop(3)) {
std::cout << "student: " << name << " | index: " << index << " | avergae: " << average << '\n';
}
/* student: Anna | index: 811111 | avergae: 4.46
student: Jane | index: 743561 | avergae: 4.44 */
for (const auto& [index, name, average] : std::views::reverse(students) | std::views::take(3)) {
std::cout << "student: " << name << " | index: " << index << " | avergae: " << average << '\n';
}
/* student: John | index: 246892 | avergae: 4.56
student: Jordan | index: 123456 | avergae: 4.53
student: Michael | index: 654321 | avergae: 4.51 */
}
```
___
## std::map
```C++
int main() {
std::map map{{1, "One"}, {2, "Two"}, {3, "Three"}, {4, "Four"}};
auto odd = [](const auto& el) { return el % 2; };
for (auto el : std::views::keys(map) | std::views::filter(odd)) {
std::cout << el << ' ';
}
std::cout << '\n';
for (const char c : map | std::views::values | std::views::join) {
std::cout << c << ' ';
}
}
```
```C++
1 3
O n e T w o T h r e e F o u r
```
___
## C++23 and further
Ranges library based on `Ranges V3`. Unfortunately, in C++20 there is a lack of useful things like creating cycles or zip functions. In C++23 there will be a few more operations like `zip` or `join_with`:
```C++
int main() {
auto x = std::vector{1, 2, 3, 4};
auto y = std::list{"α", "β", "γ", "δ", "ε"};
auto z = std::array{'A', 'B', 'C', 'D', 'E', 'F'};
/* 1 α A
2 β B
3 γ C
4 δ D */
for (const auto& [num, grec, alpha] : std::views::zip(x, y, z)) {
std::cout << num << ' ' << grec << ' ' << alpha << '\n';
}
std::map map{{1, "One"}, {2, "Two"}, {3, "Three"}, {4, "Four"}};
auto ends_with_e = [](const auto& el) { return el.back() == 'e'; };
const auto joined = std::views::values(map) | std::views::filter(ends_with_e) | std::views::join_with(' ');
/* Two Four */
for (const auto& el : joined) {
std::cout << el;
}
}
```
___
## actions (C++23)
There is a proposal to extend ranges in C++23 to allow easy convert range to container (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1206r6.pdf)
```C++
int main() {
std::map map{
{1, "Hello"}, {2, "Abcd"}, {3, "Hello"}, {4, "Aaa"}, {5, "Ala"}, {6, "Abcd"}};
// Since C++23
for (const auto& el : map
| std::views::values
| std::ranges::to // Since C++23
| std::ranges::sort
| std::ranges::unique) {
std::cout << el << '\n';
}
}
```
```C++
Aaa
Abcd
Ala
Hello
```
___
## actions (C++26)
In C+26 we should get also `operator|=`.
Before C++26
```C++
int main() {
std::vector vec{"Hello", "Abcd", "Hello", "Aaa", "Ala", "Abcd"};
std::ranges::sort(vec);
auto ret = std::ranges::unique(vec);
vec.erase(ret.begin(), ret.end());
}
```
In C++26
```C++
int main() {
std::vector vec{"Hello","Abcd", "Hello", "Aaa", "Ala", "Abcd"};
vec |= std::ranges::sort | std::ranges::unique;
}
```
___
## Exercise 1
Open project `searcher` and implement function `searchFiles` which returns all files containing `keyWord`.
Possible output:
```C++
"C:\\Users\\mateusz\\Documents\\Nokia2022\\Basic\\Course_part1\\exercises\\searcher/files\\fileA.hpp"
"C:\\Users\\mateusz\\Documents\\Nokia2022\\Basic\\Course_part1\\exercises\\searcher/files\\fileC.hpp"
```
___
## Exercise 2
Open project `students`:
* implement function `filterStudents`,
* Student should be disqualified whether his average is below `minAvergae`,
* Write an algorithm that prints students using ranges (do not implement friend operator<<)
Output:
```C++
Name: Jane | index: 743561 | average: 4.44
Name: Tom | index: 811111 | average: 4.36
Name: Mike | index: 811111 | average: 4.45
```