簡體   English   中英

C++ 迭代大小為 N 的子向量

[英]C++ iterate over subvectors of size N

我有一個可以是任意大小的輸入向量。 我想要的是將這個向量分成大小為 64 的向量並做一些事情。 輸入向量的大小不一定是 64 的倍數。

所以假設我有一個大小為 200 的向量,那么我應該將它分成 3 個大小為 64 的向量和 1 個大小為 8 的向量。

到目前為止,我想到的是以下幾點:

vector<double> inputVector;
vector<vector<double>> resultVector;

UInt16 length = inputVector.size();
int div = (length % 64) == 0 ? length / 64 : (length / 64) + 1;

for (int i = 0, j = 0; i < div; i++) {
    vector<double> current
    for (int k = 0; k < 64; k++) {
        current.push_back(inputVector[j]);
       if (j++ >= length) break;
    }
    resultVector.push_back(current);
    if (j >= length) break;
}

我相信會有更好的方法,但我找不到任何例子

您可以使用迭代器來創建子向量:

vector<double> inputVector;
vector<vector<double>> resultVector;

for (auto it = inputVector.cbegin(), e = inputVector.cend(); it != inputVector.cend(); it = e) {
    e = it + std::min<std::size_t>(inputVector.cend() - it, 64);
    resultVector.emplace_back(it, e);
}

最簡單的就是將每個元素 push_back 到某個向量,跟蹤它們,如果達到塊大小,則將它們“刷新”到輸出向量:

template<typename T>
std::vector<std::vector<T>> devide(const std::vector<T>& v, size_t chunk) {
    // iterative algorithm
    std::vector<T> tmp;
    std::vector<std::vector<T>> ret;
    size_t cnt = 0;
    for (auto&& i : v) {
        tmp.push_back(i);
        ++cnt;
        if (cnt == chunk) {
             cnt = 0;
             ret.push_back(tmp);
             tmp.clear();
        }
    }
    if (cnt != 0) {
        ret.push_back(tmp);
    }
    return ret;
}

但是這種迭代方法不是最佳的——我們可以復制大塊的內存。 因此,迭代向量並在每個循環中最多復制元素的塊數 - 並在最后一個循環中復制更少。

template<typename T>
std::vector<std::vector<T>> devide2(const std::vector<T>& v, size_t chunk) {
    // chunk algorithm
    std::vector<std::vector<T>> ret;
    const auto max = v.size();
    for (size_t i = 0; i < max; ) {
        const size_t chunkend = std::min(i + chunk, max);
        ret.emplace_back(v.begin() + i, v.begin() + chunkend);
        i = chunkend;
    }
    return ret;
}

在 Godbolt 上測試

更多 STL 風格:

void even_slice(In b, In e, size_t n, F f)
{
    while(std::distance(b, e) >= n) {
        f(b, b + n);
        b = b + n;
    }
    if (b != e) {
        f(b, e);
    }
}

template<typename In, typename Out>
Out even_slice_to_vetors(In b, In e, size_t n, Out out)
{
    using ValueType = typename std::iterator_traits<In>::value_type;
    using ItemResult = std::vector<ValueType>;
    even_slice(b, e, n, [&out](auto x, auto y) { *out++ = ItemResult{x, y}; });
    return out;
}

https://godbolt.org/z/zn9Ex1

請注意,您確切知道有多少子向量具有所需的最大大小:

template<typename It>
auto subdivide_in_chunks(It first, It last, size_t chunk_size) {
    using value_type = typename std::iterator_traits<It>::value_type;
    size_t size{ std::distance(first, last) / chunk_size };
    std::vector<std::vector<value_type>> ret;
    ret.reserve(size);
    auto last_chunk = std::next(first, size * chunk_size);
    while ( first != last_chunk ) {
        auto next = std::next(first, chunk_size);    
        ret.emplace_back(first, next);
        first = next;
    }
    ret.emplace_back(first, last);  // This is the last, shorter one. 
    return ret;
}

使用 range-v3,您可以簡單地編寫:

namespace rs = ranges;
namespace rv = ranges::views;

auto resultVector = inputVector 
                  | rv::chunk(64) 
                  | rs::to<std::vector<std::vector<double>>>;

這是一個演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM