Introduction
The function divides a range given by a begin_iterator
and an end_iterator
into n
sub-ranges of the same format, where the sub-ranges must be as equally sized as possible.
Example
Consider a set of size 10:
\$\{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 \}\$
The output would be is a set of n = 3
sub-ranges:
\$\{ \{ 0, 3 \}, \{ 4, 6 \}, \{ 7, 9 \} \}\$
Where each sub-set is as even as possible, in the previous example the sets have sizes 4, 3, and 3, respectively; that is the most even way to distribute 10 elements into 3 sub-sets.
Review goals
- Efficiency
- Correctness
Implementation
The oringinal code contained an issue which I missed by pure luck. Here is the fixed working code; the changes do not invalidate the present answer.
#include <vector> // std::vector<T>
#include <iterator> // std::distance(), std::next()
template <typename Iterator>
decltype( auto ) divide_work( Iterator begin, Iterator end, std::size_t n )
{
using size_type = std::size_t;
auto sz = std::distance( begin, end );
auto element_per_group_count = sz / n;
auto remaining_element_count = sz % n;
std::vector<std::pair<Iterator, Iterator>> ranges;
ranges.reserve( n );
if ( remaining_element_count == 0 )
{
--element_per_group_count;
ranges.emplace_back( std::make_pair( std::next( begin, 0 ),
std::next( begin, element_per_group_count ) ) );
for ( auto i = 1U; i < n; ++i )
{
auto first = std::next( ranges[ i - 1 ].second, 1 );
ranges.emplace_back( std::make_pair( first,
std::next( first, element_per_group_count ) ) );
}
}
else
{
ranges.emplace_back( std::make_pair( std::next( begin, 0 ),
std::next( begin, element_per_group_count ) ) );
for ( auto i = 1U; i < remaining_element_count; ++i )
{
auto first = std::next( ranges[ i - 1 ].second, 1 );
ranges.emplace_back( std::make_pair( first,
std::next( first, element_per_group_count ) ) );
}
--element_per_group_count;
for ( auto i = ranges.size(); i < n; ++i )
{
auto first = std::next( ranges[ i - 1 ].second, 1 );
ranges.emplace_back( std::make_pair( first,
std::next( first, element_per_group_count ) ) );
}
}
return ranges;
}
Output