Last active
July 17, 2020 20:03
-
-
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++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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