Sometimes I need to "double for loop" and since I do nothing in outer for loop for first loop variable beside passing it to inner for loop I wonder if it can be done elegantly with C 20 ranges.
Example of nested for loops I would like to "flatten".
struct Person{
std::string name = "Bjarne";
};
std::vector persons{Person{}, Person{}};
int main() {
for (const auto& person: persons) {
for (const auto& ch: person.name) {
std::cout << ch << std::endl;
}
}
}
Best what I can think of is:
std::ranges::for_each(persons | std::views::transform(&Person::name) | std::views::join, [](const char& ch){
std::cout << ch << std::endl;
});
but I wonder if there is a simpler way.
CodePudding user response:
Yeah, what you propose is correct. Except it can still be a range-based for statement, you don't have to switch to an algorithm:
for (const auto& ch : persons
| std::views::transform(&Person::name)
| std::views::join)
{
// ...
}
Most languages use the name map
instead of transform
, and flatten
instead of join
(indeed your question title asks about flattening). And then it's common to put these two together with a new algorithm called flat_map
which does both of these things together.
We can do that too:
inline constexpr auto flat_map = [](auto f){
return std::views::transform(f) | std::views::join;
};
for (const auto& ch : persons | flat_map(&Person::name))
{
// ...
}
Although in C I suppose this would be called transform_join
? Meh. flat_map
all the way.
Pro-tip: use fmt::print
to print ranges, less to write and it already comes out formatted.