[英]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;
}
}
使用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.