繁体   English   中英

将大小为 m 的 std::vector 拆分为大小为 n 的向量组成的向量

[英]Splitting std::vector of size m into vector of vectors of size n

给定一个向量[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] ,有哪些可能的方法来构造[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17]] ,主要关注可读性?

目前,我已经正确定义了所有子数组的开始和结束索引,并尝试使用std::copy(cam.begin() + start, cam.begin() + end+ 1, vec.begin()); 构造一个新的向量..导致:

terminate called after throwing an instance of 'std::bad_alloc'
what():  std::bad_alloc

如果您只是在编写一些可以将向量拆分为最多五个元素向量的向量的代码,那么应该这样做。 仅仅因为它周围的测试工具,它比必要的要大。

代码的“肉”是模板化的 function makeVecOfVecs()和对它的单行调用。 将这种事情作为模板来做是非常方便的,因为它可以很容易地扩展到其他数据类型。 代码是:

#include <iostream>
#include <vector>

// From a flat vector, construct a vector of sub-vectors, each of a
// specific size (except the last sub-vector, which may be smaller).

template<class T>
std::vector<std::vector<T>>
makeVecOfVecs(
    const std::vector<T> &in,
    unsigned int sz
) {
    std::vector<std::vector<T>> out;
    for (int i = 0; i < in.size(); i += sz) {
        if (in.size() - i < sz)
            sz = in.size() - i;

        std::vector<T> newVec(sz);
        std::copy(in.begin() + i, in.begin() + i + sz, newVec.begin());
        out.push_back(newVec);

        // As pointed out in a comment, you could probably
        // replace the three preceding lines with just:
        //    out.emplace_back(in.begin() + i, in.begin() + i + sz);
        // and avoid creating newVec.
    }

    return out;
}

// Test harness for the above function.

int main(int argc, char *argv[]) {
    // Default to 17 values, allow for override. Could probably
    // make more robust, but is IS only test code.

    int count = 17;
    if (argc > 1)
        count = atoi(argv[1]);

    // Input data for testing, print for validation.

    std::vector<int> in;
    for (int i = 0; i < count; ++i)
        in.push_back(i + 1);
    std::cout << "\nInput (" << count << "):";
    for (const auto &inElem: in)
        std::cout << " " << inElem;
    std::cout << "\n";

    auto out = makeVecOfVecs<int>(in, 5);

    // Output of result for validation.

    std::cout << "Output:\n";
    for (const auto &outElem1: out) {
        std::cout << "   ";
        for (const auto &outElem2: outElem1)
            std::cout << " " << outElem2;
        std::cout << "\n";
    }
}

下面显示了一些示例运行以进行验证(您会看到我要求的块大小为10而不是5 ,这只是为了在答案中使用更少的空间):

pax:~> for i in "" 22 20 0 -9 1; do ./testprog ${i}; done

Input (17): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Output:
    1 2 3 4 5 6 7 8 9 10
    11 12 13 14 15 16 17

Input (22): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Output:
    1 2 3 4 5 6 7 8 9 10
    11 12 13 14 15 16 17 18 19 20
    21 22

Input (20): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Output:
    1 2 3 4 5 6 7 8 9 10
    11 12 13 14 15 16 17 18 19 20

Input (0):
Output:

Input (-9):
Output:

Input (1): 1
Output:
    1

如果向量的向量被解释为矩阵,则可以通过从一维输入向量中复制段以直接的方式填充前 n-1 行。 只有该“矩阵”的最后一行需要注意,因为它可能没有完全填充。

#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
#include <cmath>

int main() {
  // create initial data
  int vecSize = 17;
  std::vector<int> inVec(vecSize);
  std::iota(inVec.begin(), inVec.end(), 1);  

  // prepare new container
  int ncol = 5;
  int nrow = std::ceil(float(vecSize) / float(ncol));  
  std::vector<std::vector<int>> outVecVec(nrow);

  // row-wise copy
  for (int i = 0; i < nrow; ++i) {
    int rowLength = ncol;
    if (i == nrow - 1 && vecSize % ncol != 0) {
      rowLength = vecSize % ncol; // length of last row, if not filled      
    }
    outVecVec[i].resize(rowLength);
    auto vecIndex = inVec.begin() + i * ncol;
    std::copy(vecIndex, vecIndex + rowLength, outVecVec[i].begin());
  }

  // print output  
   for (int i = 0; i < nrow; ++i) {
     for (int j = 0; j < outVecVec[i].size(); ++j)
       std::cout << outVecVec[i][j] << " ";
     std::cout << std::endl;
   }
}      

演示: https://godbolt.org/z/w9aDrE

使用range-v3库,这变得非常简单且易读:

std::vector<int> v = ...
int m = ...

auto vs = v | ranges::views::chunk(m) 
            | ranges::to<std::vector<std::vector<int>>>;

这是一个演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM