Разбить вектор на части

Разбить вектор на равные части длины 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 шт):

Автор решения: Maxim Timakov

Пример с 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;
});

За работоспособность не отвечаю - писал на коленке - но идея должна быть понятна.

→ Ссылка
Автор решения: Harry

А можно не согласиться? Этот код более громоздкий и некрасивый, чем применение чего-то стандартно-алгоритмического?

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;
}
→ Ссылка
Автор решения: Stanislav Volodarskiy

Этот код громоздкий, но понятный. 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;
}
→ Ссылка