Skip to content

Instantly share code, notes, and snippets.

@marcinwol
Last active July 17, 2020 20:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save marcinwol/3283a92331ff64a8f531 to your computer and use it in GitHub Desktop.
Save marcinwol/3283a92331ff64a8f531 to your computer and use it in GitHub Desktop.
Split vector, list or deque into chunks of an equal size in C++
/**
* Split container into chunks of an equal size
*
* An example C++11 function called chunker that takes
* a container (vector, list, deque), divides it
* into equal chunks of a given size, and returns
* container of chunks.
*
*
* The example code is based on the two following posts:
* http://stackoverflow.com/a/11408470/248823
* http://stackoverflow.com/a/31174124/248823
*
*
*
* Example output:
*
* Chunk size is: 2
*
* Example 1 - vector of strings
* 11, 22 | 33, 44 | 55 |
*
* Example 2 - vector of ints
* 1, 2 | 3, 4 | 5 |
*
* Example 3 list of floats
* 1.5, 2.5 | 3.5, 4.5 | 5.5 |
*
* Example 3 deque of Cats
* A-1, V-2 | C-3, D-4 | E-5, F-6 |
*
*/
#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <algorithm>
#include <stdexcept>
using namespace std;
template <
typename T,
typename A,
template <typename , typename > class C
>
C<C<T,A>, allocator<C<T,A>>>
chunker(C<T,A>& c, const typename C<T,A>::size_type& k)
{
if (k <= 0)
throw domain_error("chunker() requires k > 0");
using INPUT_CONTAINER_TYPE = C<T,A>;
using INPUT_CONTAINER_VALUE_TYPE = typename INPUT_CONTAINER_TYPE::value_type;
using OUTPUT_CONTAINER_TYPE = C<INPUT_CONTAINER_TYPE,
allocator<INPUT_CONTAINER_TYPE>
>;
OUTPUT_CONTAINER_TYPE out_c;
auto chunkBeg = begin(c);
for (auto left=c.size(); left != 0; )
{
auto const skip = min(left,k);
INPUT_CONTAINER_TYPE sub_container;
back_insert_iterator<INPUT_CONTAINER_TYPE> back_v(sub_container);
copy_n(chunkBeg, skip, back_v);
out_c.push_back(sub_container);
left -= skip;
advance(chunkBeg, skip);
}
return out_c;
}
template <typename C>
void print_nested_container(const C& container)
{
for (auto& sub_container: container)
{
size_t no_elem = sub_container.size();
size_t i {0};
for (auto& val: sub_container)
{
cout << val;
if (++i < no_elem)
cout << ", ";
}
cout << " | ";
}
}
struct Cat
{
string name;
size_t age;
};
std::ostream& operator<< (std::ostream& stream, const Cat& cat) {
std::cout << cat.name << "-" << cat.age;
return stream;
}
int main() {
size_t chunk_size {2};
cout << "Chunk size is: " << chunk_size << "\n" << endl;
// Example 1 - vector of strings
cout << "Example 1 - vector of strings" << endl;
vector<string> c1 {"11", "22", "33", "44", "55"};
vector<vector<string>> chunks1 = chunker(c1, chunk_size);
print_nested_container(chunks1);
cout << endl << endl;
// Example 2 - vector of ints
cout << "Example 2 - vector of ints" << endl;
vector<int> c2 {1, 2, 3, 4, 5};
vector<vector<int>> chunks2 = chunker(c2, chunk_size);
print_nested_container(chunks2);
cout << endl << endl;
// Example 3 list of floats
cout << "Example 3 list of floats" << endl;
list<float> c3 {1.5, 2.5, 3.5, 4.5, 5.5};
list<list<float>> chunks3 = chunker(c3, chunk_size);
print_nested_container(chunks3);
cout << endl << endl;
// Example 4 deque of Cats
cout << "Example 4 deque of Cats" << endl;
deque<Cat> c4 {Cat{"A", 1}, Cat{"V", 2},
Cat{"C", 3},Cat{"D", 4},
Cat{"E", 5},Cat{"F", 6}};
deque<deque<Cat>> chunks4 = chunker(c4, chunk_size);
print_nested_container(chunks4);
cout << endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment