Reputation: 29
I have two vectors of same length. One of them holds vectors of double :
std::vector<std::vector<double>> A;
and the second one holds doubles
std::vector<double> B;
By "the same length" I mean that A contains as many vectors of double as B contains double. I would like to iterate through both of them with a single iterator at the same time. I have a feeling I need to create a class to do that. Something like
std::vector<vector<double>>::iterator iter = A.begin();
for (A= iter.begin(); iter != A.end(); iter++)
{
(*iter).A // I access an element of A std::vector<double>
(*iter).B // I access an element of B (double)
}
I checked a similar question and this one is pretty close to what I want to do: C++ iterating over 2 vectors using for loop
but in my case the iterators have two different types, respectively std::vector<vector<double>>::iterator
and vector<double>::iterator
, so the solution of this question does not work, but I guess it is pretty close.
How can I do it? What would be the best way?
Upvotes: 2
Views: 652
Reputation: 122257
In priciple you could write a custom iterator that has a first
and a second
that reference elements of A
and B
respectively. However, custom iterators aren't simple. The easier alternative is to use a plain old index based loop:
for (size_t i = 0; i < A.size() && i < B.size(); ++i)
{
A[i]; // I access an element of A std::vector<double>
B[i]; // I access an element of B (double)
}
Or use two iterators
auto itA = A.begin();
auto itB = B.begin();
for ( ; itA != A.end() && itB != B.end(); ++itA,++itB) {
//...
}
You also might be interested in zip_iterator
from boost or view::zip
from the ranges-v3 library:
#include <iostream>
#include <vector>
#include <range/v3/view.hpp>
int main() {
std::vector<int> A{1,2,3,4,5};
std::vector<double> B{1.2,3.4,5.6,7.8,9.1};
for (const auto& [a, b] : ranges::view::zip(A, B)) {
std::cout << a << " " << b << "\n";
}
}
The standard ranges library is based on Nieblers ranges, but so far zip
didn't make it to the standard library yet. If I understood correctly, it is to be expected for C++23.
PS: Note that your for (A= iter.begin(); iter != A.end(); iter++)
can be considered "old-fashioned". Since C++11 there are range based for loops, that let you iterate elements of a container from begin till end. They go one step further in also hiding the iterators from you (they are still there) to have even less opportunities for typos. Though, just like iterator based loops are a little less flexible than index based loops, range based loops are a little less flexibe than iterator based loops. They only let you iterate from begin
till end
:
for (const auto& a : A) {
a; // a is a const reference to element in A
}
I just mention this for the sake of completeness, "zipping" two iterators into one is neither easier nor much more complicated with a range based loop as with the old iterator based loop.
Upvotes: 3