Is there any existing iterator implementation (perhaps in boost) which implement some sort of flattening iterator?
For example:
unordered_set<vector<int> > s;
s.insert(vector<int>());
s.insert({1,2,3,4,5});
s.insert({6,7,8});
s.insert({9,10,11,12});
flattening_iterator<unordered_set<vector<int> >::iterator> it( ... ), end( ... );
for(; it != end; ++it)
{
cout << *it << endl;
}
//would print the numbers 1 through 12
you can make one using iterator facade in boost.
I wrote iterator product which you can use as a template perhaps: http://code.google.com/p/asadchev/source/browse/trunk/work/cxx/iterator/product.hpp
I don't know of any implementation in a major library, but it looked like an interesting problem so I wrote a basic implementation. I've only tested it with the test case I present here, so I don't recommend using it without further testing.
The problem is a bit trickier than it looks because some of the "inner" containers may be empty and you have to skip over them. This means that advancing the
flattening_iterator
by one position may actually advance the iterator into the "outer" container by more than one position. Because of this, theflattening_iterator
needs to know where the end of the outer range is so that it knows when it needs to stop.This implementation is a forward iterator. A bidirectional iterator would also need to keep track of the beginning of the outer range. The
flatten
function templates are used to make constructingflattening_iterator
s a bit easier.The following is a minimal test stub:
Like I said at the beginning, I haven't tested this thoroughly. Let me know if you find any bugs and I'll be happy to correct them.
I decided to "improve" a bit on the flattening iterator concept, though as noted by James you are stuck using Ranges (except for the inner most container), so I just used ranges through and through and thus obtained a flattened range, with an arbitrary depth.
First I used a building brick:
And then defined a (very minimal)
ForwardRange
concept:This is our building brick here, though in fact we could make do with just the rest:
And apparently, it works
I arrive a little late here, but I have just published a library (multidim) to deal with such problem. The usage is quite simple: to use your example,
The library is header-only and has no dependencies. Requires C++11 though.