Visual C++ 2015 std::unordered_set performance - c++

I wrote a very simple program to benchmark the performance of std::set<int> vs std::unordered_set<int>. When I run this program on GCC, unordered_set is much faster. But if I run the same code on Visual C++ 2015, set clearly outperforms unordered_set.
Am I missing something obvious? I've searched around for anything that mentions performance problems with unordered_set on Visual C++ but I haven't found anything. Of course, I am running in Release mode with all the usual optimizations turned on.
Here are the results, the 1st column is proportional to the amount of times insert is called, set is the 2nd column and unordered_setis the 3rd. The timings are in microseconds, the lower the better.
// with GCC 4.9.2
1 23.208 11.323
2 31.705 10.805
3 41.113 11.671
4 51.124 12.742
5 60.941 13.931
6 69.642 14.083
7 75.245 15.151
8 84.227 15.983
9 93.464 17.415
10 102.419 18.036
11 121.212 19.979
12 129.748 20.908
13 140.378 22.201
14 151.061 23.131
15 151.483 23.289
16 162.107 24.252
17 170.408 24.746
18 175.369 25.73
19 184.257 26.835
20 192.877 29.459
21 214.805 30.461
22 223.105 30.977
23 221.382 31.037
24 230.129 32.398
// with Visual C++ 2015
1 24.761 32.473
2 31.075 47.305
3 39.309 58.974
4 44.749 73.753
5 51.608 81.204
6 58.141 96.035
7 67.309 106.105
8 75.653 118.712
9 80.801 126.99
10 88.548 144.899
11 95.388 165.135
12 105.546 170.017
13 108.9 177.442
14 117.891 192.446
15 125.177 194.573
16 130.842 212.399
17 138.182 242.828
18 144.113 240.621
19 151.28 262.748
20 158.495 265.814
21 168.463 277.699
22 178.542 295.593
23 181.643 304.112
24 191.779 317.013
And here is the code I wrote:
#include <iostream>
#include <set>
#include <unordered_set>
#include <chrono>
template<typename T>
T InsertTest(const int count, const int repeat)
{
T set;
for (int k = 0; k < repeat; ++k)
{
for (int i = 0; i < count; ++i)
{
set.insert(i * (repeat + 1));
}
}
return set;
}
int main()
{
for (int repeat = 1; repeat < 25; ++repeat)
{
std::cout << repeat << '\t';
{
const auto beg = std::chrono::high_resolution_clock::now();
InsertTest<std::set<int>>(100000, repeat);
const auto end = std::chrono::high_resolution_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - beg).count() / 1000.0f << '\t';
}
{
const auto beg = std::chrono::high_resolution_clock::now();
InsertTest<std::unordered_set<int>>(100000, repeat);
const auto end = std::chrono::high_resolution_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - beg).count() / 1000.0f << '\t';
}
std::cout << std::endl;
}
}

Related

how to build a two three series program in C++

i have this CS question that says:
We will define a series two three to be a series whose first term is some natural number. If the value of the member number n in the series is x, then the value of the (n +1)th member in the series is: (x % 2 ==0) ? x/2 : x*3 +1.
You must write a program that prints two or three series starting with the numbers 1 to twenty-five (not inclusive), but the creation of each series will stop when a value greater than a thousand or a value that has already appeared in a previous series is produced (and therefore the sub-series that was produced from this array onwards has already been produced). The value that is produced must be displayed again, thus stopping the production of the series.
now the code i have written outputs a similar result to the solution output but it needs some changes in order to get the same exact result which i couldn't figure out, this is my code.
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main()
{
int array[25];
for (int i = 1; i < 25; i++)
{
int currentNum = i;
int theNumAfter;
bool occured = false;
while (occured == false)
{
for (int i = 0; i <= 25; i++)
{
if (array[i] == currentNum)
{
occured = true;
cout << endl;
}
}
array[currentNum] = currentNum;
cout << currentNum << " ";
if (currentNum % 2 == 0)
{
theNumAfter = currentNum / 2;
}
else
{
theNumAfter = (3 * currentNum) + 1;
}
array[theNumAfter] = theNumAfter;
cout << theNumAfter << " ";
currentNum = theNumAfter;
}
}
}
the code doesn't take any input and there is only one right output which should be this:
1 4 2 1
2
3 10 5 16 8 4
4
5
6 3
7 22 11 34 17 52 26 13 40 20 10
8
9 28 14 7
10
11
12 6
13
14
15 46 23 70 35 106 53 160 80 40
16
17
18 9
19 58 29 88 44 22
20
21 64 32 16
22
23
24 12
the result of my code:
1 4
4 2
2 1 3 10
10 5
4 2
5 16 6 3
3 10 7 22
22 11 8 4
4 2 9 28 28 14
14 7
10 5
11 34 12 6
6 3 13 40 40 20
20 10
14 7 15 46 46 23
23 70
16 8 17 52 52 26 26 13
13 40 18 9
9 28 19 58 58 29 29 88 88 44 44 22
22 11
what should i change in the code, so we have matching outputs. thanks in advance
the creation of each series will stop when a value greater than a thousand or a value that has already appeared in a previous series is produced.
Up to 24, none of the produced values is greater than a thousand, but the posted code still has an access out of bounds bug:
int main()
{
int array[25];
// ^^
for (int i = 1; i < 25; i++)
{
int currentNum = i;
int theNumAfter;
// ...
array[currentNum] = currentNum;
// ...
array[theNumAfter] = theNumAfter;
// ...
}
// ...
}
Note the many of numbers in the expected output are greater than 25.
I'm not sure what this part was supposed to achive:
for (int i = 0; i <= 25; i++)
{ // ^^^^^^^ it "checks" only the first 25 values that may occur
if (array[i] == currentNum)
{
occured = true;
cout << endl; // <-- The duplicate should be printed before the newline.
// Here it should break out of the loop.
}
}
array[currentNum] = currentNum;
cout << currentNum << " ";
But it fails to produce the expected output.
I'd use a simple array of 1000 bools to memorize the already occurred numbers.
#include <iostream>
int main()
{
constexpr int limit{ 1'000 };
bool already_seen[limit + 1]{};
for (int i = 1; i < 25; i++)
{
int current{ i };
while ( current <= limit and not already_seen[current] )
{
std::cout << current << ' ';
already_seen[current] = true;
if ( current % 2 == 0)
{
current /= 2;
}
else
{
current = (3 * current) + 1;
}
}
std::cout << current << '\n';
}
}
Testable here.

How to relocate an element in one array in C++

I took this interview question and I failed, so I'm here to not fail again!
I have an array of int with size 16 and a 5 < givenIndex < 10.
I have to take the element in this index a print every possible array (there are 16) by moving the element at givenIndex through every position in array and pushing rest of elements.
For example:
int array[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
int givenIndex = 6;
Since array[givenIndex] = 7, I need to move 7 to every possible position and print that array.
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
[7,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16]
[1,7,2,3,4,5,6,8,9,10,11,12,13,14,15,16]
[1,2,7,3,4,5,6,8,9,10,11,12,13,14,15,16]
And that's for 16 cases.
What I was trying was:
for(int i = 0;i<16;i++){
array[i] = array[indexInsercion]
if (i<indexInsert){
//right shift
array[i] = array[i+1]
}else if(i == indexInsert){
//no shift
}else{
//left shift
array[i] = array[i-1]
}
}
Can I get some help?
We can only guess what the interviewer expected to see. If I was the interviewer I would like to see that you keep things simple. This is code I think one can expect to be written from scratch in an interview situation:
#include <iostream>
#include <array>
template <size_t size>
void print_replaced(const std::array<int,size>& x,size_t index){
for (int i=0;i<size;++i){
for (int j=0;j<i;++j) {
if (j == index) continue;
std::cout << x[j] << " ";
}
std::cout << x[index] << " ";
for (int j=i;j<size;++j) {
if (j == index) continue;
std::cout << x[j] << " ";
}
std::cout << "\n";
}
}
int main() {
std::array<int,16> x{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
print_replaced(x,6);
}
It is a first approach at the problem, with a loop that prints 16 different combinations of the array elements. Printing each line follows simple logic: We print all elements before the one that should be replaced, then the one that should be shuffled, then the remaining elements.
It is simple, but wrong. Its output is:
7 1 2 3 4 5 6 8 9 10 11 12 13 14 15 16
1 7 2 3 4 5 6 8 9 10 11 12 13 14 15 16
1 2 7 3 4 5 6 8 9 10 11 12 13 14 15 16
1 2 3 7 4 5 6 8 9 10 11 12 13 14 15 16
1 2 3 4 7 5 6 8 9 10 11 12 13 14 15 16
1 2 3 4 5 7 6 8 9 10 11 12 13 14 15 16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 2 3 4 5 6 8 7 9 10 11 12 13 14 15 16
1 2 3 4 5 6 8 9 7 10 11 12 13 14 15 16
1 2 3 4 5 6 8 9 10 7 11 12 13 14 15 16
1 2 3 4 5 6 8 9 10 11 7 12 13 14 15 16
1 2 3 4 5 6 8 9 10 11 12 7 13 14 15 16
1 2 3 4 5 6 8 9 10 11 12 13 7 14 15 16
1 2 3 4 5 6 8 9 10 11 12 13 14 7 15 16
1 2 3 4 5 6 8 9 10 11 12 13 14 15 7 16
There is one line that appears twice and the last line is missing.
As an interviewer I would not be surprised that the first attempt does not produce correct output. I don't care about that. Thats not a minus. What I would care about is how you react on that. Do you know the next steps? Do you have a strategy to fix the wrong output? Or do you just panic because you didn't manage to write the correct code on the first attempt? This is what I would like to check in an interview and then thats the end of the exercise. I want to ask more different questions rather than giving you the time to fix all mistakes and write correct well tested code, because I know that this takes more time than we have in the interview.
I'll leave it to you to fix the above code ;)
Here's a quick stab at it. Basically just keep track of where the given index should go and print it there as well as skip the original position it would be in.
#include <iostream>
int main()
{
int array[16] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
int givenIndex = 6;
for (int p = 0; p <= 16; ++p)
{
if (p != givenIndex)
{
std::cout << "[";
for (int i = 0; i < 16; ++i)
{
if (i == p)
{
if (i > 0)
{
std::cout << ",";
}
std::cout << array[givenIndex];
}
if (array[i] != array[givenIndex])
{
if (i > 0 || p == 0)
{
std::cout << ",";
}
std::cout << array[i];
}
}
if (p == 16)
{
std::cout << "," << array[givenIndex];
}
std::cout << "]\n";
}
}
}
Output:
[7,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16]
[1,7,2,3,4,5,6,8,9,10,11,12,13,14,15,16]
[1,2,7,3,4,5,6,8,9,10,11,12,13,14,15,16]
[1,2,3,7,4,5,6,8,9,10,11,12,13,14,15,16]
[1,2,3,4,7,5,6,8,9,10,11,12,13,14,15,16]
[1,2,3,4,5,7,6,8,9,10,11,12,13,14,15,16]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
[1,2,3,4,5,6,8,7,9,10,11,12,13,14,15,16]
[1,2,3,4,5,6,8,9,7,10,11,12,13,14,15,16]
[1,2,3,4,5,6,8,9,10,7,11,12,13,14,15,16]
[1,2,3,4,5,6,8,9,10,11,7,12,13,14,15,16]
[1,2,3,4,5,6,8,9,10,11,12,7,13,14,15,16]
[1,2,3,4,5,6,8,9,10,11,12,13,7,14,15,16]
[1,2,3,4,5,6,8,9,10,11,12,13,14,7,15,16]
[1,2,3,4,5,6,8,9,10,11,12,13,14,15,7,16]
[1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,7]
If the expectation is to just print the elements of array in the given order:
Keep the track of current index of array element to be print, say indx -
If the position of current element processing is equal to row number then
print the element at givenIndex.
If indx is equal to givenIndex skip it and print indx + 1 element, otherwise print element at indx and increase indx by 1.
Implementation:
#include <iostream>
#include <array>
int main() {
std::array<int, 16> array = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
std::size_t givenIndex = 6;
for (std::size_t i = 0, indx = 0; i < array.size(); indx = 0, ++i) {
std::cout << '[';
for (std::size_t j = 0; j < array.size(); ++j) {
if (j == i) {
std::cout << array[givenIndex] << ',';
continue;
}
if (indx == givenIndex) {
++indx;
}
std::cout << array[indx++] << ',';
}
std::cout << ']';
std::cout << '\n';
}
return 0;
}
Output:
# ./a.out
[7,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,]
[1,7,2,3,4,5,6,8,9,10,11,12,13,14,15,16,]
[1,2,7,3,4,5,6,8,9,10,11,12,13,14,15,16,]
[1,2,3,7,4,5,6,8,9,10,11,12,13,14,15,16,]
[1,2,3,4,7,5,6,8,9,10,11,12,13,14,15,16,]
[1,2,3,4,5,7,6,8,9,10,11,12,13,14,15,16,]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,]
[1,2,3,4,5,6,8,7,9,10,11,12,13,14,15,16,]
[1,2,3,4,5,6,8,9,7,10,11,12,13,14,15,16,]
[1,2,3,4,5,6,8,9,10,7,11,12,13,14,15,16,]
[1,2,3,4,5,6,8,9,10,11,7,12,13,14,15,16,]
[1,2,3,4,5,6,8,9,10,11,12,7,13,14,15,16,]
[1,2,3,4,5,6,8,9,10,11,12,13,7,14,15,16,]
[1,2,3,4,5,6,8,9,10,11,12,13,14,7,15,16,]
[1,2,3,4,5,6,8,9,10,11,12,13,14,15,7,16,]
[1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,7,]
If the expectation is to alter the order of elements in the array and then print the array:
First move the element at givenIndex to the 0th index of array and then -
Print array
In every iteration swap the current element with its next element in the array and print it.
Implementation:
#include <iostream>
#include <array>
void print_array (std::array<int, 16>& array) {
std::cout << '[';
for (std::size_t indx = 0; indx < array.size(); ++indx) {
std::cout << array[indx] << ',';
}
std::cout << ']';
std::cout << '\n';
}
void rearrange_array_elem (std::array<int, 16>& array, std::size_t givenIndx) {
// move the element at givneIndx to first position in array
for (std::size_t j = givenIndx; j > 0; --j) {
std::swap (array[j], array[j - 1]);
}
// print array
print_array (array);
for (std::size_t indx = 0; indx < array.size() - 1; ++indx) {
// swap current element with its next element
std::swap (array[indx], array[indx + 1]);
print_array (array);
}
}
int main() {
std::array<int, 16> array = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
std::size_t givenIndex = 6;
rearrange_array_elem (array, givenIndex);
return 0;
}
Output:
# ./a.out
[7,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,]
[1,7,2,3,4,5,6,8,9,10,11,12,13,14,15,16,]
[1,2,7,3,4,5,6,8,9,10,11,12,13,14,15,16,]
[1,2,3,7,4,5,6,8,9,10,11,12,13,14,15,16,]
[1,2,3,4,7,5,6,8,9,10,11,12,13,14,15,16,]
[1,2,3,4,5,7,6,8,9,10,11,12,13,14,15,16,]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,]
[1,2,3,4,5,6,8,7,9,10,11,12,13,14,15,16,]
[1,2,3,4,5,6,8,9,7,10,11,12,13,14,15,16,]
[1,2,3,4,5,6,8,9,10,7,11,12,13,14,15,16,]
[1,2,3,4,5,6,8,9,10,11,7,12,13,14,15,16,]
[1,2,3,4,5,6,8,9,10,11,12,7,13,14,15,16,]
[1,2,3,4,5,6,8,9,10,11,12,13,7,14,15,16,]
[1,2,3,4,5,6,8,9,10,11,12,13,14,7,15,16,]
[1,2,3,4,5,6,8,9,10,11,12,13,14,15,7,16,]
[1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,7,]

g++ optimization breakes for loop

So, I have this codesnippet here
for (int t = WILSON_TEMPORAL_START, t_i = 0; t <= WILSON_TEMPORAL_END; t++, t_i++)
{
for (int r = WILSON_SPATIAL_START, r_i = 0; r <= WILSON_SPATIAL_END; r++, r_i++)
{
std::cout << r << " " << WILSON_SPATIAL_END << std::endl;
wilson_loop[conf_id][t_i][r_i] = compute_wilson_loop(t, r, iu1, iu2);
}
}
I run my g++ compiler in two different optimization versions -O1 and -O2, but the terminal output is differently.
With -O1
2 12
3 12
4 12
5 12
6 12
7 12
8 12
9 12
10 12
11 12
12 12
2 12
3 12
4 12
...
With -O2
2 12
3 12
4 12
5 12
6 12
7 12
8 12
9 12
10 12
11 12
12 12
13 12
14 12
15 12
...
The code works fine if I change the inner loop to:
for (int t = WILSON_TEMPORAL_START, t_i = 0; t <= WILSON_TEMPORAL_END; t++, t_i++)
{
for (int r = WILSON_SPATIAL_START, r_i = 0; r <= WILSON_SPATIAL_END; r++, r_i++)
{
std::cout << r << " " << WILSON_SPATIAL_END << std::endl;
// wilson_loop[conf_id][t_i][r_i] =
compute_wilson_loop(t, r, iu1, iu2);
}
}
Some useful definitions are:
static double compute_wilson_loop(int time_extend, int space_extend, SUN_mat iu1[VOL][DIM], SUN_mat iu2[VOL][DIM])
void wilson::measure_wilson_loop(SUN_mat pu[VOL][DIM], double wilson_loop[CLEN][TLEN][SLEN], int conf_id) {
...
}
I know, that I can find a workaround here, but I really want to understand, why this happens.
I just solved the problem, I made an error in defining the preprocessor constants. I'm still not sure, why it changes output when using a different optimization mode, but it works now :)

Memory access failure in my RNG function, while using memcpy

I'm getting a memory access failure while i try to copy the element from my random array.
I have no clue what i am doing wrong, thx for your help in advance.
Here is my code:
1 #include <TSS_API_RNG.h>
2
3 using namespace std;
4
5 // dummy rng for internal speed tests
6 void rng(uint8_t out[], size_t len) {
7
8 unsigned char iv[len];
9 size_t i, k;
10 srand(time(NULL));
11 for (i = 0; i < len; i++) {
12 k = rand()%256;
13 iv[i] = (unsigned char)k;
14 cout << iv[i] << endl;
15
16 memcpy(&out[0], &iv[0], len);
17 cout << &out[0] << endl;
18 memset(&iv[0], 0x00, len);
19 }
20 }
21
22 int main() {
23
24 rng(NULL, 10);
25 return 0;
26 }
And this is what happens when i try to execute my programme:
pi#raspberrypi:~/projects/RNG_final $ ./DUMMY_RNG
▒
Speicherzugriffsfehler
I must be using the memcopy function not correctly, but i have no idea how to solve this issue. For testing i wanted to pass 10 random numbers, but it fails at the first iteration of memcpy. The loop itselfe works properly, hence it prints the value in the first cout value correctly.
Thx guys, managed to fix the issue with your advice.
My code:
1 #include <TSS_API_RNG.h>
2
3 using namespace std;
4
5 // constructor
6 DUMMY_RNG::DUMMY_RNG()
7 :r_len(0), r_count(0)
8 {
9 std::cout << "Neue Instanz" << std::endl;
10 }
11
12
13 // destructor
14 DUMMY_RNG::~DUMMY_RNG(void)
15 {
16 }
17
18
19 // dummy rng for internal speed tests
20 int DUMMY_RNG::rng(uint8_t out[], size_t len) {
21
22 unsigned char iv[len];
23 size_t k;
24 srand(time(NULL));
25 //for (i = 0; i < len; i++) {
26 k = rand()%256;
27 iv[0] = (unsigned char)k;
28
29 memcpy(&out[0], &iv[0], len);
30 memset(&iv[0], 0x00, len);
31 //}
32 return 1;
33 }
34
35
36 // randomize function replacement from botan rng class
37 void DUMMY_RNG::randomize(uint8_t out[], size_t len)
38 {
39 r_count += 1;
40 r_len += len;
41
42 rng(out, len);
43 }

Splitting std::vector of size m into vector of vectors of size n

Given a vector [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
what are some possible approaches to construct [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17]], focusing primarily on readability?
At the moment, I have correctly defined the starting and ending indexes of all the subarrays, and was trying to use std::copy(cam.begin() + start, cam.begin() + end+ 1, vec.begin()); to construct a new vector.. resulting in:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
If you're just after some code that can split a vector into a vector of up-to-five-element vectors, this should do it. It's bigger than necessary only because of the test harness around it.
The "meat" of the code is the templated function makeVecOfVecs(), and the single-line call to it. It's quite handy to do this sort of thing as a template since it then becomes easy to extend to other data types. The code is:
#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";
}
}
A few sample runs are shown below for validation (you'll see I've asked for a chunk size of 10 rather than 5, that's just to use less space in the answer):
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
If the vector of vectors is interpreted as a matrix, the first n-1 rows can be filled in a straightforward way by copying segments from the one-dimensional input vector. Only the last row of that "matrix" requires some attention, as it may not be completely filled.
#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;
}
}
demo: https://godbolt.org/z/w9aDrE
Using the range-v3 library this becomes very simple, and readable:
std::vector<int> v = ...
int m = ...
auto vs = v | ranges::views::chunk(m)
| ranges::to<std::vector<std::vector<int>>>;
Here's a demo.