I have two vectors. I want to iterate over all elements of both and do something (say print them out). So I could write something like:
vector<int> vec_a{1, 2, 3}, vec_b{4, 5, 6, 7};
for (auto a : vec_a) {
cout << a;
}
for (auto b : vec_b) {
cout << b;
}
This has a lot of duplication. I could do something like:
for (const auto& vec : {vec_a, vec_b}) {
for (auto elem : vec) {
cout << elem;
}
}
But this adds an extra for
(which is not too bad but I'm wondering if there is something better. Something along the lines of:
for (auto elem : concat(vec_a, vec_b)) {
cout << elem;
}
I know I could just concat the vectors (a la Concatenating two std::vectors) but that syntax is even clunkier (especially since I actually have 4 vectors).
I want the output to be:
1 2 3 4 5 6 7
Use std:vector as your default sequential container, especially as an alternative to built-in arrays If you add or remove elements frequently at both the front and back of a container, use std::deque Use a std::list (not std::deque) if you need to insert/remove elements in the middle of the sequence
This article focuses on discussing all the methods that can be used to iterate over a set in C++. The following methods will be discussed in this article: Iterate over a set using an iterator. Iterate over a set in backward direction using reverse_iterator. Iterate over a set using range-based for loop. Iterate over a set using for_each loop.
For better understanding of iteration of multiple lists, we are iterating over 3 lists at a time. zip () : In Python 3, zip returns an iterator. zip () function stops when anyone of the list of all the lists gets exhausted. In simple words, it runs till the smallest of all the lists.
Let’s start discussing each of these methods in detail. Iterating over a set using iterator. In this method, an iterator itr is created and initialized using begin () function which will point to the first element, and after every iteration, itr points to the next element in a set and it will continue to iterate until it reaches the end of the set.
A simple solution is to use a helper function:
#include <functional>
template <typename Func, typename... Containers>
void for_all(Func&& func, Containers&&... containers) {
auto iteration_func = [&](auto&& container) {
for (auto&& elem : std::forward<decltype(container)>(container)) {
std::invoke(func, std::forward<decltype(elem)>(elem));
}
};
(iteration_func(std::forward<Containers>(containers)), ...);
}
Here, we use a fold expression with an immediately invoked lambda to simulate a loop over the variadic template arguments, where each of them is looped over and the provided function object is invoked on its elements.
The use of forwarding references and invocations to std::forward
preserve the value categories of arguments and elements, for compatibility with rvalue ranges (e.g., move_view
from the range-v3 library). std::invoke
generalizes the notion of function objects to pointers to members, which can be useful in certain cases.
Example:
int main() {
std::vector<int> vec_a{1, 2, 3};
std::vector<int> vec_b{4, 5, 6, 7};
for_all([](int n) {
std::cout << n << ' ';
}, vec_a, vec_b);
std::cout << '\n';
}
(wandbox)
Different container types can be mixed:
for_all([](const auto& n) {
std::cout << n << ' ';
}, std::vector{1, 2, 3}, std::list{"foo", "bar"});
There is nice range library which works with C++14
and in large part will become part of C++20.
In this library there is ranges::views::concat
which does exactly what you need in nice clean way:
#include <iostream>
#include <ranges>
#include <vector>
#include <array>
#include <functional>
#include <range/v3/view/concat.hpp>
int main()
{
using ranges::views::concat;
auto a = std::vector<int>{ 1, 2, 6, 7 };
auto b = std::array<int , 2>{ 1, 3 };
auto c = { -1, -4, 7, 8, 9, 11};
for (auto x : concat(a, b)) {
std::cout << x << ", ";
}
std::cout << "\n--\n";
for (auto x : concat(c, a, b)) {
std::cout << x << ", ";
}
return 0;
}
https://godbolt.org/z/Waf3Ma
Sadly concat
is not available in C++20 (can't find it in documentation and gcc do not support it).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With