Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>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.</p> <p>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 <code>flattening_iterator</code> by one position may actually advance the iterator into the "outer" container by more than one position. Because of this, the <code>flattening_iterator</code> needs to know where the end of the outer range is so that it knows when it needs to stop.</p> <p>This implementation is a forward iterator. A bidirectional iterator would also need to keep track of the beginning of the outer range. The <code>flatten</code> function templates are used to make constructing <code>flattening_iterator</code>s a bit easier.</p> <pre><code>#include &lt;iterator&gt; // A forward iterator that "flattens" a container of containers. For example, // a vector&lt;vector&lt;int&gt;&gt; containing { { 1, 2, 3 }, { 4, 5, 6 } } is iterated as // a single range, { 1, 2, 3, 4, 5, 6 }. template &lt;typename OuterIterator&gt; class flattening_iterator { public: typedef OuterIterator outer_iterator; typedef typename OuterIterator::value_type::iterator inner_iterator; typedef std::forward_iterator_tag iterator_category; typedef typename inner_iterator::value_type value_type; typedef typename inner_iterator::difference_type difference_type; typedef typename inner_iterator::pointer pointer; typedef typename inner_iterator::reference reference; flattening_iterator() { } flattening_iterator(outer_iterator it) : outer_it_(it), outer_end_(it) { } flattening_iterator(outer_iterator it, outer_iterator end) : outer_it_(it), outer_end_(end) { if (outer_it_ == outer_end_) { return; } inner_it_ = outer_it_-&gt;begin(); advance_past_empty_inner_containers(); } reference operator*() const { return *inner_it_; } pointer operator-&gt;() const { return &amp;*inner_it_; } flattening_iterator&amp; operator++() { ++inner_it_; if (inner_it_ == outer_it_-&gt;end()) advance_past_empty_inner_containers(); return *this; } flattening_iterator operator++(int) { flattening_iterator it(*this); ++*this; return it; } friend bool operator==(const flattening_iterator&amp; a, const flattening_iterator&amp; b) { if (a.outer_it_ != b.outer_it_) return false; if (a.outer_it_ != a.outer_end_ &amp;&amp; b.outer_it_ != b.outer_end_ &amp;&amp; a.inner_it_ != b.inner_it_) return false; return true; } friend bool operator!=(const flattening_iterator&amp; a, const flattening_iterator&amp; b) { return !(a == b); } private: void advance_past_empty_inner_containers() { while (outer_it_ != outer_end_ &amp;&amp; inner_it_ == outer_it_-&gt;end()) { ++outer_it_; if (outer_it_ != outer_end_) inner_it_ = outer_it_-&gt;begin(); } } outer_iterator outer_it_; outer_iterator outer_end_; inner_iterator inner_it_; }; template &lt;typename Iterator&gt; flattening_iterator&lt;Iterator&gt; flatten(Iterator it) { return flattening_iterator&lt;Iterator&gt;(it, it); } template &lt;typename Iterator&gt; flattening_iterator&lt;Iterator&gt; flatten(Iterator first, Iterator last) { return flattening_iterator&lt;Iterator&gt;(first, last); } </code></pre> <p>The following is a minimal test stub:</p> <pre><code>#include &lt;algorithm&gt; #include &lt;iostream&gt; #include &lt;set&gt; #include &lt;vector&gt; int main() { // Generate some test data: it looks like this: // { { 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 } } std::vector&lt;std::vector&lt;int&gt;&gt; v(3); int i(0); for (auto it(v.begin()); it != v.end(); ++it) { it-&gt;push_back(i++); it-&gt;push_back(i++); it-&gt;push_back(i++); it-&gt;push_back(i++); } // Flatten the data and print all the elements: for (auto it(flatten(v.begin(), v.end())); it != v.end(); ++it) { std::cout &lt;&lt; *it &lt;&lt; ", "; } std::cout &lt;&lt; "\n"; // Or, since the standard library algorithms are awesome: std::copy(flatten(v.begin(), v.end()), flatten(v.end()), std::ostream_iterator&lt;int&gt;(std::cout, ", ")); } </code></pre> <p><em>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.</em></p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload