Разбить вектор на части
Разбить вектор на равные части длины n: допускается, что в конце останется часть меньшего размера. Пример: массив размера 10, его нужно разбить на блоки длины n = 3
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
Какие есть варианты разбиения с помощью встроенных функций C++? Простой проход циклом выглядит громоздко и некрасиво, особенно если последняя часть размера < n.
Ответы (3 шт):
Пример с std::accumulate:
#include <algorythm>
using DataType = int;
using Data = std::vector<DataType>;
using Result = std::vector<Data>;
Data data;
size_t slice_sz = 3;
auto result = std::accumulate(data.begin() data.end(), Result{}, [slice_sz](Result r, DataType d) -> Result
{
if (r.empty() || r.back().size() == slice_sz)
{
r.emplace_back();
r.back().reserve(slice_sz);
}
r.back().emplace_back(d);
return r;
});
За работоспособность не отвечаю - писал на коленке - но идея должна быть понятна.
А можно не согласиться? Этот код более громоздкий и некрасивый, чем применение чего-то стандартно-алгоритмического?
vector<vector<int>> split(const vector<int>& v, size_t n)
{
vector<vector<int>> r;
for(size_t i = 0, S = v.size(), m = (S+n-1)/n; i < m; ++i)
r.emplace_back(v.begin()+i*n,v.begin()+i*n+(i==m-1&&S%n?S%n:n));
return r;
}
Для Stanislav Volodarskiy — более обобщенный вариант:
template<typename Iterator>
vector<vector<typename Iterator::value_type>>
split(Iterator b, Iterator e, size_t n)
{
vector<vector<typename Iterator::value_type>> r;
while(b != e)
{
Iterator start = b; // Запомнили, откуда брать очередное
size_t m = n;
while(m-- && b != e) b = next(b); // Цикл или до n, или до конца
r.emplace_back(start,b);
}
return r;
}
Этот код громоздкий, но понятный. from, to - пара итераторов на расстоянии n. Когда оба итератора упираются в end они становятся равны, цикл прерывается:
vector<vector<int>> split(const vector<int> &v, size_t n) {
const auto end = v.end();
vector<vector<int>> result;
auto from = v.begin();
for (; ; ) {
auto to = (static_cast<size_t>(end - from) > n) ? from + n : end;
if (to == from) {
break;
}
result.emplace_back(from, to);
from = to;
}
return result;
}