Related
C++11 provides multiple ways to iterate over containers. For example:
Range-based loop
for(auto c : container) fun(c)
std::for_each
for_each(container.begin(),container.end(),fun)
However what is the recommended way to iterate over two (or more) containers of the same size to accomplish something like:
for(unsigned i = 0; i < containerA.size(); ++i) {
containerA[i] = containerB[i];
}
Rather late to the party. But: I would iterate over indices. But not with the classical for loop but instead with a range-based for loop over the indices:
for(unsigned i : indices(containerA)) {
containerA[i] = containerB[i];
}
indices is a simple wrapper function which returns a (lazily evaluated) range for the indices. Since the implementation – though simple – is a bit too long to post it here, you can find an implementation on GitHub.
This code is as efficient as using a manual, classical for loop.
If this pattern occurs often in your data, consider using another pattern which zips two sequences and produces a range of tuples, corresponding to the paired elements:
for (auto& [a, b] : zip(containerA, containerB)) {
a = b;
}
The implementation of zip is left as an exercise for the reader, but it follows easily from the implementation of indices.
(Before C++17 you’d have to write the following instead:)
for (auto&& items : zip(containerA, containerB))
get<0>(items) = get<1>(items);
i wonder why no one mentioned this:
auto itA = vectorA.begin();
auto itB = vectorB.begin();
while(itA != vectorA.end() || itB != vectorB.end())
{
if(itA != vectorA.end())
{
++itA;
}
if(itB != vectorB.end())
{
++itB;
}
}
PS: if the container sizes don't match, then you may need to put each container specific code into its corresponding if block.
For your specific example, just use
std::copy_n(contB.begin(), contA.size(), contA.begin())
For the more general case, you can use Boost.Iterator's zip_iterator, with a small function to make it usable in range-based for loops. For most cases, this will work:
template<class... Conts>
auto zip_range(Conts&... conts)
-> decltype(boost::make_iterator_range(
boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))))
{
return {boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))};
}
// ...
for(auto&& t : zip_range(contA, contB))
std::cout << t.get<0>() << " : " << t.get<1>() << "\n";
Live example.
However, for full-blown genericity, you probably want something more like this, which will work correctly for arrays and user-defined types that don't have member begin()/end() but do have begin/end functions in their namespace. Also, this will allow the user to specifically get const access through the zip_c... functions.
And if you're an advocate of nice error messages, like me, then you probably want this, which checks if any temporary containers were passed to any of the zip_... functions, and prints a nice error message if so.
There are a lot of ways to do specific things with multiple containers as provided in the algorithm header. For instance, in the example you've given, you could use std::copy instead of an explicit for loop.
On the other hand, there isn't any built-in way to generically iterate multiple containers other than a normal for loop. This isn't surprising because there are a lot of ways to iterate. Think about it: you could iterate through one container with one step, one container with another step; or through one container until it gets to the end then start inserting while you go through to the end of the other container; or one step of the first container for every time you completely go through the other container then start over; or some other pattern; or more than two containers at a time; etc ...
However, if you wanted to make your own "for_each" style function that iterates through two containers only up to the length of the shortest one, you could do something like this:
template <typename Container1, typename Container2>
void custom_for_each(
Container1 &c1,
Container2 &c2,
std::function<void(Container1::iterator &it1, Container2::iterator &it2)> f)
{
Container1::iterator begin1 = c1.begin();
Container2::iterator begin2 = c2.begin();
Container1::iterator end1 = c1.end();
Container2::iterator end2 = c2.end();
Container1::iterator i1;
Container2::iterator i2;
for (i1 = begin1, i2 = begin2; (i1 != end1) && (i2 != end2); ++it1, ++i2) {
f(i1, i2);
}
}
Obviously you can make any kind of iterations strategy you want in a similar way.
Of course, you might argue that just doing the inner for loop directly is easier than writing a custom function like this ... and you'd be right, if you are only going to do it one or two times. But the nice thing is that this is very reusable. =)
In case when you need to iterate simultaneously over 2 containers only, there is an extended version of standard for_each algorithm in boost range library, e.g:
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/bind.hpp>
#include <boost/range/algorithm_ext/for_each.hpp>
void foo(int a, int& b)
{
b = a + 1;
}
int main()
{
std::vector<int> contA = boost::assign::list_of(4)(3)(5)(2);
std::vector<int> contB(contA.size(), 0);
boost::for_each(contA, contB, boost::bind(&foo, _1, _2));
// contB will be now 5,4,6,3
//...
return 0;
}
When you need to handle more than 2 containers in one algorithm, then you need to play with zip.
another solution could be capturing a reference of the iterator of the other container in a lambda and using post increment operator on that. for example simple copy would be:
vector<double> a{1, 2, 3};
vector<double> b(3);
auto ita = a.begin();
for_each(b.begin(), b.end(), [&ita](auto &itb) { itb = *ita++; })
inside lambda you can do whatever with ita and then increment it. This easily extends to the multiple containers case.
A range-library provides this and other very helpful functionality. The following example uses Boost.Range. Eric Niebler's rangev3 should be a good alternative.
#include <boost/range/combine.hpp>
#include <iostream>
#include <vector>
#include <list>
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& i: boost::combine(v, l))
{
int ti;
char tc;
boost::tie(ti,tc) = i;
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
C++17 will make this even better with structured bindings:
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& [ti, tc]: boost::combine(v, l))
{
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
I'm a bit late too; but you can use this (C-style variadic function):
template<typename T>
void foreach(std::function<void(T)> callback, int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
std::vector<T> v = va_arg(args, std::vector<T>);
std::for_each(v.begin(), v.end(), callback);
}
va_end(args);
}
foreach<int>([](const int &i) {
// do something here
}, 6, vecA, vecB, vecC, vecD, vecE, vecF);
or this (using a function parameter pack):
template<typename Func, typename T>
void foreach(Func callback, std::vector<T> &v) {
std::for_each(v.begin(), v.end(), callback);
}
template<typename Func, typename T, typename... Args>
void foreach(Func callback, std::vector<T> &v, Args... args) {
std::for_each(v.begin(), v.end(), callback);
return foreach(callback, args...);
}
foreach([](const int &i){
// do something here
}, vecA, vecB, vecC, vecD, vecE, vecF);
or this (using a brace-enclosed initializer list):
template<typename Func, typename T>
void foreach(Func callback, std::initializer_list<std::vector<T>> list) {
for (auto &vec : list) {
std::for_each(vec.begin(), vec.end(), callback);
}
}
foreach([](const int &i){
// do something here
}, {vecA, vecB, vecC, vecD, vecE, vecF});
or you can join vectors like here: What is the best way to concatenate two vectors? and then iterate over big vector.
I personally prefer using what is already in the STL (in the <algorithm> header) if possible. std::transform has a signature that can take two input iterators. So at least for the case of two input containers you could do:
std::transform(containerA.begin(), containerA.end(), containerB.begin(), outputContainer.begin(), [&](const auto& first, const auto& second){
return do_operation(first, second);
});
Note that the outputContainer can also be one of the input containers. But one limitation is that you cannot do a post update operation if you are modifying one of the containers in place.
The answer is here!... when C++23 comes.
#include <algorithm>
#include <forward_list>
#include <ranges>
#include <array>
#include <iostream>
int main()
{
auto foos = std::to_array({ 1, 2, 3, 4, 5 });
auto woos = std::to_array({ 6, 7, 8, 9, 10 });
auto fooswoos = std::views::zip(foos,woos);
for(auto [foo, woo] : fooswoos) {
woo += foo;
}
std::ranges::for_each(woos, [](const auto& e) { std::cout << e << '\n'; });
return 0;
}
So, what's happening?
We are constructing a special "view". This view allows us to look at containers as if they were other structures without actually doing any copying or anything like that. Using a structured binding we are able to take a reference to each aligning element per iteration and do whatever we want to it (and safely)
Check it out on compiler explorer right now!
Here is one variant
template<class ... Iterator>
void increment_dummy(Iterator ... i)
{}
template<class Function,class ... Iterator>
void for_each_combined(size_t N,Function&& fun,Iterator... iter)
{
while(N!=0)
{
fun(*iter...);
increment_dummy(++iter...);
--N;
}
}
Example usage
void arrays_mix(size_t N,const float* x,const float* y,float* z)
{
for_each_combined(N,[](float x,float y,float& z){z=x+y;},x,y,z);
}
C++11 provides multiple ways to iterate over containers. For example:
Range-based loop
for(auto c : container) fun(c)
std::for_each
for_each(container.begin(),container.end(),fun)
However what is the recommended way to iterate over two (or more) containers of the same size to accomplish something like:
for(unsigned i = 0; i < containerA.size(); ++i) {
containerA[i] = containerB[i];
}
Rather late to the party. But: I would iterate over indices. But not with the classical for loop but instead with a range-based for loop over the indices:
for(unsigned i : indices(containerA)) {
containerA[i] = containerB[i];
}
indices is a simple wrapper function which returns a (lazily evaluated) range for the indices. Since the implementation – though simple – is a bit too long to post it here, you can find an implementation on GitHub.
This code is as efficient as using a manual, classical for loop.
If this pattern occurs often in your data, consider using another pattern which zips two sequences and produces a range of tuples, corresponding to the paired elements:
for (auto& [a, b] : zip(containerA, containerB)) {
a = b;
}
The implementation of zip is left as an exercise for the reader, but it follows easily from the implementation of indices.
(Before C++17 you’d have to write the following instead:)
for (auto&& items : zip(containerA, containerB))
get<0>(items) = get<1>(items);
i wonder why no one mentioned this:
auto itA = vectorA.begin();
auto itB = vectorB.begin();
while(itA != vectorA.end() || itB != vectorB.end())
{
if(itA != vectorA.end())
{
++itA;
}
if(itB != vectorB.end())
{
++itB;
}
}
PS: if the container sizes don't match, then you may need to put each container specific code into its corresponding if block.
For your specific example, just use
std::copy_n(contB.begin(), contA.size(), contA.begin())
For the more general case, you can use Boost.Iterator's zip_iterator, with a small function to make it usable in range-based for loops. For most cases, this will work:
template<class... Conts>
auto zip_range(Conts&... conts)
-> decltype(boost::make_iterator_range(
boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))))
{
return {boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))};
}
// ...
for(auto&& t : zip_range(contA, contB))
std::cout << t.get<0>() << " : " << t.get<1>() << "\n";
Live example.
However, for full-blown genericity, you probably want something more like this, which will work correctly for arrays and user-defined types that don't have member begin()/end() but do have begin/end functions in their namespace. Also, this will allow the user to specifically get const access through the zip_c... functions.
And if you're an advocate of nice error messages, like me, then you probably want this, which checks if any temporary containers were passed to any of the zip_... functions, and prints a nice error message if so.
There are a lot of ways to do specific things with multiple containers as provided in the algorithm header. For instance, in the example you've given, you could use std::copy instead of an explicit for loop.
On the other hand, there isn't any built-in way to generically iterate multiple containers other than a normal for loop. This isn't surprising because there are a lot of ways to iterate. Think about it: you could iterate through one container with one step, one container with another step; or through one container until it gets to the end then start inserting while you go through to the end of the other container; or one step of the first container for every time you completely go through the other container then start over; or some other pattern; or more than two containers at a time; etc ...
However, if you wanted to make your own "for_each" style function that iterates through two containers only up to the length of the shortest one, you could do something like this:
template <typename Container1, typename Container2>
void custom_for_each(
Container1 &c1,
Container2 &c2,
std::function<void(Container1::iterator &it1, Container2::iterator &it2)> f)
{
Container1::iterator begin1 = c1.begin();
Container2::iterator begin2 = c2.begin();
Container1::iterator end1 = c1.end();
Container2::iterator end2 = c2.end();
Container1::iterator i1;
Container2::iterator i2;
for (i1 = begin1, i2 = begin2; (i1 != end1) && (i2 != end2); ++it1, ++i2) {
f(i1, i2);
}
}
Obviously you can make any kind of iterations strategy you want in a similar way.
Of course, you might argue that just doing the inner for loop directly is easier than writing a custom function like this ... and you'd be right, if you are only going to do it one or two times. But the nice thing is that this is very reusable. =)
In case when you need to iterate simultaneously over 2 containers only, there is an extended version of standard for_each algorithm in boost range library, e.g:
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/bind.hpp>
#include <boost/range/algorithm_ext/for_each.hpp>
void foo(int a, int& b)
{
b = a + 1;
}
int main()
{
std::vector<int> contA = boost::assign::list_of(4)(3)(5)(2);
std::vector<int> contB(contA.size(), 0);
boost::for_each(contA, contB, boost::bind(&foo, _1, _2));
// contB will be now 5,4,6,3
//...
return 0;
}
When you need to handle more than 2 containers in one algorithm, then you need to play with zip.
another solution could be capturing a reference of the iterator of the other container in a lambda and using post increment operator on that. for example simple copy would be:
vector<double> a{1, 2, 3};
vector<double> b(3);
auto ita = a.begin();
for_each(b.begin(), b.end(), [&ita](auto &itb) { itb = *ita++; })
inside lambda you can do whatever with ita and then increment it. This easily extends to the multiple containers case.
A range-library provides this and other very helpful functionality. The following example uses Boost.Range. Eric Niebler's rangev3 should be a good alternative.
#include <boost/range/combine.hpp>
#include <iostream>
#include <vector>
#include <list>
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& i: boost::combine(v, l))
{
int ti;
char tc;
boost::tie(ti,tc) = i;
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
C++17 will make this even better with structured bindings:
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& [ti, tc]: boost::combine(v, l))
{
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
I'm a bit late too; but you can use this (C-style variadic function):
template<typename T>
void foreach(std::function<void(T)> callback, int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
std::vector<T> v = va_arg(args, std::vector<T>);
std::for_each(v.begin(), v.end(), callback);
}
va_end(args);
}
foreach<int>([](const int &i) {
// do something here
}, 6, vecA, vecB, vecC, vecD, vecE, vecF);
or this (using a function parameter pack):
template<typename Func, typename T>
void foreach(Func callback, std::vector<T> &v) {
std::for_each(v.begin(), v.end(), callback);
}
template<typename Func, typename T, typename... Args>
void foreach(Func callback, std::vector<T> &v, Args... args) {
std::for_each(v.begin(), v.end(), callback);
return foreach(callback, args...);
}
foreach([](const int &i){
// do something here
}, vecA, vecB, vecC, vecD, vecE, vecF);
or this (using a brace-enclosed initializer list):
template<typename Func, typename T>
void foreach(Func callback, std::initializer_list<std::vector<T>> list) {
for (auto &vec : list) {
std::for_each(vec.begin(), vec.end(), callback);
}
}
foreach([](const int &i){
// do something here
}, {vecA, vecB, vecC, vecD, vecE, vecF});
or you can join vectors like here: What is the best way to concatenate two vectors? and then iterate over big vector.
I personally prefer using what is already in the STL (in the <algorithm> header) if possible. std::transform has a signature that can take two input iterators. So at least for the case of two input containers you could do:
std::transform(containerA.begin(), containerA.end(), containerB.begin(), outputContainer.begin(), [&](const auto& first, const auto& second){
return do_operation(first, second);
});
Note that the outputContainer can also be one of the input containers. But one limitation is that you cannot do a post update operation if you are modifying one of the containers in place.
The answer is here!... when C++23 comes.
#include <algorithm>
#include <forward_list>
#include <ranges>
#include <array>
#include <iostream>
int main()
{
auto foos = std::to_array({ 1, 2, 3, 4, 5 });
auto woos = std::to_array({ 6, 7, 8, 9, 10 });
auto fooswoos = std::views::zip(foos,woos);
for(auto [foo, woo] : fooswoos) {
woo += foo;
}
std::ranges::for_each(woos, [](const auto& e) { std::cout << e << '\n'; });
return 0;
}
So, what's happening?
We are constructing a special "view". This view allows us to look at containers as if they were other structures without actually doing any copying or anything like that. Using a structured binding we are able to take a reference to each aligning element per iteration and do whatever we want to it (and safely)
Check it out on compiler explorer right now!
Here is one variant
template<class ... Iterator>
void increment_dummy(Iterator ... i)
{}
template<class Function,class ... Iterator>
void for_each_combined(size_t N,Function&& fun,Iterator... iter)
{
while(N!=0)
{
fun(*iter...);
increment_dummy(++iter...);
--N;
}
}
Example usage
void arrays_mix(size_t N,const float* x,const float* y,float* z)
{
for_each_combined(N,[](float x,float y,float& z){z=x+y;},x,y,z);
}
Is there a nice way to iterate over at most N elements in a container using a range-based for loop and/or algorithms from the standard library (that's the whole point, I know I can just use the "old" for loop with a condition).
Basically, I'm looking for something that corresponds to this Python code:
for i in arr[:N]:
print(i)
As I personally would use either this or this answer (+1 for both), just for increasing your knowledge - there are boost adapters you can use. For your case - the sliced seems the most appropriate:
#include <boost/range/adaptor/sliced.hpp>
#include <vector>
#include <iostream>
int main(int argc, const char* argv[])
{
std::vector<int> input={1,2,3,4,5,6,7,8,9};
const int N = 4;
using boost::adaptors::sliced;
for (auto&& e: input | sliced(0, N))
std::cout << e << std::endl;
}
One important note: N is required by sliced to be not greater than distance(range) - so safer(and slower) version is as follows:
for (auto&& e: input | sliced(0, std::min(N, input.size())))
So - once again - I would use simpler, old C/C++ approach (this you wanted to avoid in your question ;)
Here is the cheapest save solution that works for all forward iterators I could come up with:
auto begin = std::begin(range);
auto end = std::end(range);
if (std::distance(begin, end) > N)
end = std::next(begin,N);
This might run through the range almost twice, but I see no other way to get the length of the range.
You can use the good old break to manually break a loop when needed. It works even with range based loop.
#include <vector>
#include <iostream>
int main() {
std::vector<int> a{2, 3, 4, 5, 6};
int cnt = 0;
int n = 3;
for (int x: a) {
if (cnt++ >= n) break;
std::cout << x << std::endl;
}
}
C++ is great since you can code your own hideous solutions and hide them under an abstraction layer
#include <vector>
#include <iostream>
//~-~-~-~-~-~-~- abstraction begins here ~-~-~-~-~-//
struct range {
range(std::vector<int>& cnt) : m_container(cnt),
m_end(cnt.end()) {}
range& till(int N) {
if (N >= m_container.size())
m_end = m_container.end();
else
m_end = m_container.begin() + N;
return *this;
}
std::vector<int>& m_container;
std::vector<int>::iterator m_end;
std::vector<int>::iterator begin() {
return m_container.begin();
}
std::vector<int>::iterator end() {
return m_end;
}
};
//~-~-~-~-~-~-~- abstraction ends here ~-~-~-~-~-//
int main() {
std::vector<int> a{11, 22, 33, 44, 55};
int n = 4;
range subRange(a);
for ( int i : subRange.till(n) ) {
std::cout << i << std::endl; // prints 11, then 22, then 33, then 44
}
}
Live Example
The above code obviously lacks some error checking and other adjustments, but I wanted to just express the idea clearly.
This works since range-based for loops produce code similar to the following
{
auto && __range = range_expression ;
for (auto __begin = begin_expr,
__end = end_expr;
__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
cfr. begin_expr and end_expr
If your container doesn't have (or might not have) RandomAccessIterator, there is still a way to skin this cat:
int cnt = 0;
for(auto it=container.begin(); it != container.end() && cnt < N ; ++it,++cnt) {
//
}
At least for me, it is very readable :-). And it has O(N) complexity regardless of container type.
This is an index iterator. Mostly boilerplate, leaving it out, because I'm lazy.
template<class T>
struct indexT
//: std::iterator< /* ... */ > // or do your own typedefs, or don't bother
{
T t = {};
indexT()=default;
indexT(T tin):t(tin){}
indexT& operator++(){ ++t; return *this; }
indexT operator++(int){ auto tmp = *this; ++t; return tmp; }
T operator*()const{return t;}
bool operator==( indexT const& o )const{ return t==o.t; }
bool operator!=( indexT const& o )const{ return t!=o.t; }
// etc if you want full functionality.
// The above is enough for a `for(:)` range-loop
};
it wraps a scalar type T, and on * returns a copy. It also works on iterators, amusingly, which is useful here, as it lets us inherit effectively from a pointer:
template<class ItA, class ItB>
struct indexing_iterator:indexT<ItA> {
ItB b;
// TODO: add the typedefs required for an iterator here
// that are going to be different than indexT<ItA>, like value_type
// and reference etc. (for simple use, not needed)
indexing_iterator(ItA a, ItB bin):ItA(a), b(bin) {}
indexT<ItA>& a() { return *this; }
indexT<ItA> const& a() const { return *this; }
decltype(auto) operator*() {
return b[**a()];
}
decltype(auto) operator->() {
return std::addressof(b[**a()]);
}
};
The indexing iterator wraps two iterators, the second of which must be random-access. It uses the first iterator to get an index, which it uses to look up a value from the second.
Next, we have is a range type. A SFINAE-improved one can be found many places. It makes iterating over a range of iterators in a for(:) loop easy:
template<class Iterator>
struct range {
Iterator b = {};
Iterator e = {};
Iterator begin() { return b; }
Iterator end() { return e; }
range(Iterator s, Iterator f):b(s),e(f) {}
range(Iterator s, size_t n):b(s), e(s+n) {}
range()=default;
decltype(auto) operator[](size_t N) { return b[N]; }
decltype(auto) operator[] (size_t N) const { return b[N]; }\
decltype(auto) front() { return *b; }
decltype(auto) back() { return *std::prev(e); }
bool empty() const { return begin()==end(); }
size_t size() const { return end()-begin(); }
};
Here are helpers to make working with ranges of indexT easy:
template<class T>
using indexT_range = range<indexT<T>>;
using index = indexT<size_t>;
using index_range = range<index>;
template<class C>
size_t size(C&&c){return c.size();}
template<class T, std::size_t N>
size_t size(T(&)[N]){return N;}
index_range indexes( size_t start, size_t finish ) {
return {index{start},index{finish}};
}
template<class C>
index_range indexes( C&& c ) {
return make_indexes( 0, size(c) );
}
index_range intersect( index_range lhs, index_range rhs ) {
if (lhs.b.t > rhs.e.t || rhs.b.t > lhs.b.t) return {};
return {index{(std::max)(lhs.b.t, rhs.b.t)}, index{(std::min)(lhs.e.t, rhs.e.t)}};
}
ok, almost there.
index_filter_it takes a range of indexes and a random access iterator, and makes a range of indexed iterators into that random access iterator's data:
template<class R, class It>
auto index_filter_it( R&& r, It it ) {
using std::begin; using std::end;
using ItA = decltype( begin(r) );
using R = range<indexing_iterator<ItA, It>>;
return R{{begin(r),it}, {end(r),it}};
}
index_filter takes an index_range and a random access container, intersects their indexes, then calls index_filter_it:
template<class C>
auto index_filter( index_range r, C& c ) {
r = intersect( r, indexes(c) );
using std::begin;
return index_filter_it( r, begin(c) );
}
and now we have:
for (auto&& i : index_filter( indexes(0,6), arr )) {
}
and viola, we have a large musical instrument.
live example
Fancier filters are possible.
size_t filter[] = {1,3,0,18,22,2,4};
using std::begin;
for (auto&& i : index_filter_it( filter, begin(arr) ) )
will visit 1, 3, 0, 18, 22, 2, 4 in arr. It does not, however, bounds-check, unless arr.begin()[] bounds-checks.
There are probably errors in the above code, and you should probably just use boost.
If you implement - and [] on indexT, you can even daisy chain these ranges.
Since C++20 you can add the range adaptor std::views::take from the Ranges library to your range-based for loop. This way you can implement a similar solution to the one in PiotrNycz's answer, but without using Boost:
int main() {
std::vector<int> v {1, 2, 3, 4, 5, 6, 7, 8, 9};
const int N = 4;
for (int i : v | std::views::take(N))
std::cout << i << std::endl;
return 0;
}
The nice thing about this solution is that N may be larger than the size of the vector. This means, for the example above, it is safe to use N = 13; the complete vector will then be printed.
Code on Wandbox
This solution doesn't go past end(), has O(N) complexity for std::list (doesn't use std::distance) works with std::for_each, and only requires ForwardIterator:
std::vector<int> vect = {1,2,3,4,5,6,7,8};
auto stop_iter = vect.begin();
const size_t stop_count = 5;
if(stop_count <= vect.size())
{
std::advance(stop_iter, n)
}
else
{
stop_iter = vect.end();
}
std::for_each(vect.vegin(), stop_iter, [](auto val){ /* do stuff */ });
The only thing it doesn't do is work with InputIterator such as std::istream_iterator - you'll have to use external counter for that.
First we write an iterator which stops at a given index:
template<class I>
class at_most_iterator
: public boost::iterator_facade<at_most_iterator<I>,
typename I::value_type,
boost::forward_traversal_tag>
{
private:
I it_;
int index_;
public:
at_most_iterator(I it, int index) : it_(it), index_(index) {}
at_most_iterator() {}
private:
friend class boost::iterator_core_access;
void increment()
{
++it_;
++index_;
}
bool equal(at_most_iterator const& other) const
{
return this->index_ == other.index_ || this->it_ == other.it_;
}
typename std::iterator_traits<I>::reference dereference() const
{
return *it_;
}
};
We can now write an algorithme for making a rage of this iterator from a given range:
template<class X>
boost::iterator_range<
at_most_iterator<typename X::iterator>>
at_most(int i, X& xs)
{
typedef typename X::iterator iterator;
return std::make_pair(
at_most_iterator<iterator>(xs.begin(), 0),
at_most_iterator<iterator>(xs.end(), i)
);
}
Usage:
int main(int argc, char** argv)
{
std::vector<int> xs = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for(int x : at_most(5, xs))
std::cout << x << "\n";
return 0;
}
C++11 provides multiple ways to iterate over containers. For example:
Range-based loop
for(auto c : container) fun(c)
std::for_each
for_each(container.begin(),container.end(),fun)
However what is the recommended way to iterate over two (or more) containers of the same size to accomplish something like:
for(unsigned i = 0; i < containerA.size(); ++i) {
containerA[i] = containerB[i];
}
Rather late to the party. But: I would iterate over indices. But not with the classical for loop but instead with a range-based for loop over the indices:
for(unsigned i : indices(containerA)) {
containerA[i] = containerB[i];
}
indices is a simple wrapper function which returns a (lazily evaluated) range for the indices. Since the implementation – though simple – is a bit too long to post it here, you can find an implementation on GitHub.
This code is as efficient as using a manual, classical for loop.
If this pattern occurs often in your data, consider using another pattern which zips two sequences and produces a range of tuples, corresponding to the paired elements:
for (auto& [a, b] : zip(containerA, containerB)) {
a = b;
}
The implementation of zip is left as an exercise for the reader, but it follows easily from the implementation of indices.
(Before C++17 you’d have to write the following instead:)
for (auto&& items : zip(containerA, containerB))
get<0>(items) = get<1>(items);
i wonder why no one mentioned this:
auto itA = vectorA.begin();
auto itB = vectorB.begin();
while(itA != vectorA.end() || itB != vectorB.end())
{
if(itA != vectorA.end())
{
++itA;
}
if(itB != vectorB.end())
{
++itB;
}
}
PS: if the container sizes don't match, then you may need to put each container specific code into its corresponding if block.
For your specific example, just use
std::copy_n(contB.begin(), contA.size(), contA.begin())
For the more general case, you can use Boost.Iterator's zip_iterator, with a small function to make it usable in range-based for loops. For most cases, this will work:
template<class... Conts>
auto zip_range(Conts&... conts)
-> decltype(boost::make_iterator_range(
boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))))
{
return {boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))};
}
// ...
for(auto&& t : zip_range(contA, contB))
std::cout << t.get<0>() << " : " << t.get<1>() << "\n";
Live example.
However, for full-blown genericity, you probably want something more like this, which will work correctly for arrays and user-defined types that don't have member begin()/end() but do have begin/end functions in their namespace. Also, this will allow the user to specifically get const access through the zip_c... functions.
And if you're an advocate of nice error messages, like me, then you probably want this, which checks if any temporary containers were passed to any of the zip_... functions, and prints a nice error message if so.
There are a lot of ways to do specific things with multiple containers as provided in the algorithm header. For instance, in the example you've given, you could use std::copy instead of an explicit for loop.
On the other hand, there isn't any built-in way to generically iterate multiple containers other than a normal for loop. This isn't surprising because there are a lot of ways to iterate. Think about it: you could iterate through one container with one step, one container with another step; or through one container until it gets to the end then start inserting while you go through to the end of the other container; or one step of the first container for every time you completely go through the other container then start over; or some other pattern; or more than two containers at a time; etc ...
However, if you wanted to make your own "for_each" style function that iterates through two containers only up to the length of the shortest one, you could do something like this:
template <typename Container1, typename Container2>
void custom_for_each(
Container1 &c1,
Container2 &c2,
std::function<void(Container1::iterator &it1, Container2::iterator &it2)> f)
{
Container1::iterator begin1 = c1.begin();
Container2::iterator begin2 = c2.begin();
Container1::iterator end1 = c1.end();
Container2::iterator end2 = c2.end();
Container1::iterator i1;
Container2::iterator i2;
for (i1 = begin1, i2 = begin2; (i1 != end1) && (i2 != end2); ++it1, ++i2) {
f(i1, i2);
}
}
Obviously you can make any kind of iterations strategy you want in a similar way.
Of course, you might argue that just doing the inner for loop directly is easier than writing a custom function like this ... and you'd be right, if you are only going to do it one or two times. But the nice thing is that this is very reusable. =)
In case when you need to iterate simultaneously over 2 containers only, there is an extended version of standard for_each algorithm in boost range library, e.g:
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/bind.hpp>
#include <boost/range/algorithm_ext/for_each.hpp>
void foo(int a, int& b)
{
b = a + 1;
}
int main()
{
std::vector<int> contA = boost::assign::list_of(4)(3)(5)(2);
std::vector<int> contB(contA.size(), 0);
boost::for_each(contA, contB, boost::bind(&foo, _1, _2));
// contB will be now 5,4,6,3
//...
return 0;
}
When you need to handle more than 2 containers in one algorithm, then you need to play with zip.
another solution could be capturing a reference of the iterator of the other container in a lambda and using post increment operator on that. for example simple copy would be:
vector<double> a{1, 2, 3};
vector<double> b(3);
auto ita = a.begin();
for_each(b.begin(), b.end(), [&ita](auto &itb) { itb = *ita++; })
inside lambda you can do whatever with ita and then increment it. This easily extends to the multiple containers case.
A range-library provides this and other very helpful functionality. The following example uses Boost.Range. Eric Niebler's rangev3 should be a good alternative.
#include <boost/range/combine.hpp>
#include <iostream>
#include <vector>
#include <list>
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& i: boost::combine(v, l))
{
int ti;
char tc;
boost::tie(ti,tc) = i;
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
C++17 will make this even better with structured bindings:
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& [ti, tc]: boost::combine(v, l))
{
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
I'm a bit late too; but you can use this (C-style variadic function):
template<typename T>
void foreach(std::function<void(T)> callback, int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
std::vector<T> v = va_arg(args, std::vector<T>);
std::for_each(v.begin(), v.end(), callback);
}
va_end(args);
}
foreach<int>([](const int &i) {
// do something here
}, 6, vecA, vecB, vecC, vecD, vecE, vecF);
or this (using a function parameter pack):
template<typename Func, typename T>
void foreach(Func callback, std::vector<T> &v) {
std::for_each(v.begin(), v.end(), callback);
}
template<typename Func, typename T, typename... Args>
void foreach(Func callback, std::vector<T> &v, Args... args) {
std::for_each(v.begin(), v.end(), callback);
return foreach(callback, args...);
}
foreach([](const int &i){
// do something here
}, vecA, vecB, vecC, vecD, vecE, vecF);
or this (using a brace-enclosed initializer list):
template<typename Func, typename T>
void foreach(Func callback, std::initializer_list<std::vector<T>> list) {
for (auto &vec : list) {
std::for_each(vec.begin(), vec.end(), callback);
}
}
foreach([](const int &i){
// do something here
}, {vecA, vecB, vecC, vecD, vecE, vecF});
or you can join vectors like here: What is the best way to concatenate two vectors? and then iterate over big vector.
I personally prefer using what is already in the STL (in the <algorithm> header) if possible. std::transform has a signature that can take two input iterators. So at least for the case of two input containers you could do:
std::transform(containerA.begin(), containerA.end(), containerB.begin(), outputContainer.begin(), [&](const auto& first, const auto& second){
return do_operation(first, second);
});
Note that the outputContainer can also be one of the input containers. But one limitation is that you cannot do a post update operation if you are modifying one of the containers in place.
The answer is here!... when C++23 comes.
#include <algorithm>
#include <forward_list>
#include <ranges>
#include <array>
#include <iostream>
int main()
{
auto foos = std::to_array({ 1, 2, 3, 4, 5 });
auto woos = std::to_array({ 6, 7, 8, 9, 10 });
auto fooswoos = std::views::zip(foos,woos);
for(auto [foo, woo] : fooswoos) {
woo += foo;
}
std::ranges::for_each(woos, [](const auto& e) { std::cout << e << '\n'; });
return 0;
}
So, what's happening?
We are constructing a special "view". This view allows us to look at containers as if they were other structures without actually doing any copying or anything like that. Using a structured binding we are able to take a reference to each aligning element per iteration and do whatever we want to it (and safely)
Check it out on compiler explorer right now!
Here is one variant
template<class ... Iterator>
void increment_dummy(Iterator ... i)
{}
template<class Function,class ... Iterator>
void for_each_combined(size_t N,Function&& fun,Iterator... iter)
{
while(N!=0)
{
fun(*iter...);
increment_dummy(++iter...);
--N;
}
}
Example usage
void arrays_mix(size_t N,const float* x,const float* y,float* z)
{
for_each_combined(N,[](float x,float y,float& z){z=x+y;},x,y,z);
}
I have a class with an accessor member function that I want to call and apply the result to a functor using std::for_each. I have a working version below that uses a for loop and for_each, but the for_each version is cryptic and cumbersome. Is there a way I can make the for_each version more concise, considering I have access to boost, but not C++11?
#if 0
// for loop version:
for(value_vector_type::iterator it = values.begin(); it!=values.end(); it++){
avg(it->getValue()); // I want to put this in a for_each loop
}
#else
// bind version:
std::for_each(values.begin(), values.end(), // iterate over all values
boost::bind(
boost::mem_fn(&average_type::operator()), // attach the averaging functor to the output of the getvalue call
&avg,
boost::bind(
boost::mem_fn(&value_wrapper_type::getValue), // bind the getValue call to each element in values
_1
)
)
);
#endif
Here is the full working implementation:
#include <vector>
#include <algorithm>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/bind/mem_fn.hpp>
// A value wrapper
template<typename T>
struct Value {
Value(){}
Value(const T& value, bool valid = true):m_value(value),m_valid(valid){}
T getValue(){ return m_value; }
bool getValid(){ return m_valid; }
void setValue(const T& value){ m_value = value; }
void setValid(const T& valid){ m_valid = valid; }
private:
T m_value;
bool m_valid;
};
// Class that calculates the average piecewise
template<typename T>
struct Average {
private:
T m_numPoints;
T m_ChannelSum;
public:
Average() : m_numPoints(0), m_ChannelSum(0.0){}
void operator()(T value){
m_numPoints++;
m_ChannelSum+=value;
}
double getAverage(){ return m_ChannelSum/m_numPoints; }
T getCount(){ return m_numPoints; }
T getSum(){ return m_ChannelSum; }
};
// Run the average computation on several values
int main(int argc, char** argv){
typedef int value_type;
typedef Value<value_type> value_wrapper_type;
typedef std::vector<value_wrapper_type> value_vector_type;
value_vector_type values;
values.push_back(value_wrapper_type(5));
values.push_back(value_wrapper_type(7));
values.push_back(value_wrapper_type(3));
values.push_back(value_wrapper_type(1));
values.push_back(value_wrapper_type(2));
typedef Average<value_type> average_type;
average_type avg;
#if 0
// for loop version:
for(value_vector_type::iterator it = values.begin(); it!=values.end(); it++){
avg(it->getValue()); // I want to put this in a for_each loop
}
#else
// bind version:
std::for_each(values.begin(), values.end(), // iterate over all values
boost::bind(
boost::mem_fn(&average_type::operator()), // attach the averaging functor to the output of the getvalue call
&avg,
boost::bind(
boost::mem_fn(&value_wrapper_type::getValue), // bind the getValue call to each element in values
_1
)
)
);
#endif
std::cout << "Average: " << avg.getAverage() << " Count: " << avg.getCount() << " Sum: " << avg.getSum() << std::endl;
}
note: my original question was how to construct a for_each at all, but I've found that solution and a whole new question did not make much sense.
Thanks, all help is really appreciated!
If you don't have C++11 but Boost you could try a bind() expression (which would also work with C++2011 as bind() is part of C++2011):
std::for_each(a.begin(), a.end(), bind(&avg<value_type>, bind(&Value<value_type>::getValue, _1)));
if you are using c++11 then you can try
for(auto& a: values)
avg(a->getValue());
or
std::for_each(a.begin(), a.end(), [](whatever_type& wt){
avg(wt->getValue());
});
If you are not, then I think that toy have as good as your going to get although formatting wont hurt.
for(value_vector_type::iterator it = values.begin();
it!=values.end();
++it)
{
avg(it.getValue()); // I want to put this in a for_each loop
}
Trying to be too clever with function object and the like can often have the inverse effect of obscuring your code.
One way to make it look neater is to use Boost.Phoenix. You can shorten down to this:
std::for_each(values.begin(), values.end(), lazy(avg)(arg1.getValue()));
Heres how to do that. First thing you need to do is make the avg function object lazy. The simplest way to that is in-place with a function, defined like this:
template<class Function>
function<Function> lazy(Function x)
{
return function<Function>(x);
}
Next thing you need to do is write a function object for getValue, that can be lazy, like this:
struct get_value_impl
{
// result_of protocol:
template <typename Sig>
struct result;
template <typename This, typename T>
struct result<This(Value<T>&)>
{
// The result will be T
typedef typename T type;
};
template <typename V>
typename result<get_value_impl(V &)>::type
operator()(V & value) const
{
return value.getValue();
}
};
Thirdly, we extend the phoenix actors, using our get_value_impl class, so it will have a getValue method, like this:
template <typename Expr>
struct value_actor
: actor<Expr>
{
typedef actor<Expr> base_type;
typedef value_actor<Expr> that_type;
value_actor( base_type const& base )
: base_type( base ) {}
typename expression::function<get_value_impl, that_type>::type const
getValue() const
{
function<get_value_impl> const f = get_value_impl();
return f(*this);
}
};
Finally, we put it all together by defining the argument and passing it into the for_each algorithm:
expression::terminal<phoenix::argument<1>, value_actor> arg1;
std::for_each(values.begin(), values.end(), lazy(avg)(arg1.getValue()));
Credit goes to Mathias Gaunard on the boost.users mailing list for pointing me towards this solution:
std::for_each(values.begin(), values.end(),
boost::bind(boost::ref(avg), boost::bind(&value_wrapper_type::getValue, _1))
);
Wrapping avg with boost::ref is required because otherwise a copy of avg is filled out with the results of getValue(), rather than avg itself.
Here is the full compiled and tested solution:
#include <stdexcept>
#include <vector>
#include <algorithm>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/bind/mem_fn.hpp>
// A value wrapper
template<typename T>
struct Value {
Value(){}
Value(const T& value, bool valid = true):m_value(value),m_valid(valid){}
T getValue(){ return m_value; }
bool getValid(){ return m_valid; }
void setValue(const T& value){ m_value = value; }
void setValid(const T& valid){ m_valid = valid; }
private:
T m_value;
bool m_valid;
};
// Class that calculates the average piecewise
template<typename T>
struct Average {
private:
T m_numPoints;
T m_ChannelSum;
public:
typedef void result_type;
Average() : m_numPoints(0), m_ChannelSum(0.0){}
result_type operator()(T value){
m_numPoints++;
m_ChannelSum+=value;
}
double getAverage(){
if (m_ChannelSum==0) {
throw std::logic_error("Cannot get average of zero values");
}
return m_ChannelSum/m_numPoints;
}
T getCount(){ return m_numPoints; }
T getSum(){ return m_ChannelSum; }
};
// Run the average computation on several values
int main(int argc, char** argv){
typedef int value_type;
typedef Value<value_type> value_wrapper_type;
typedef std::vector<value_wrapper_type> value_vector_type;
value_vector_type values;
values.push_back(value_wrapper_type(5));
values.push_back(value_wrapper_type(7));
values.push_back(value_wrapper_type(3));
values.push_back(value_wrapper_type(1));
values.push_back(value_wrapper_type(2));
typedef Average<value_type> average_type;
average_type avg;
#if 0
// for loop version:
for(value_vector_type::iterator it = values.begin(); it!=values.end(); it++){
avg(it->getValue()); // I want to put this in a for_each loop
}
#else
// bind version:
std::for_each(values.begin(), values.end(),
boost::bind(boost::ref(avg), boost::bind(&value_wrapper_type::getValue, _1))
);
#endif
std::cout << "Average: " << avg.getAverage() << " Count: " << avg.getCount() << " Sum: " << avg.getSum() << std::endl;
}
If you can use boost, but not C++11 features, then I would consider using the BOOST_FOREACH macro
Yes, it's a macro, but as macros go it's well behaved
It's also reads quite nicely and is hard to get wrong
BOOST_FOREACH(const Value& rValue, values)
{
avg(rValue.getValue());
}
C++11 range based for loops will replace it