Convert 1D vector to 2D vector - c++

I got a compiling error when using std::copy to convert a 1D vector to a 2D vector.
int main()
{
std::vector< std::vector<float> > v2D(10, std::vector<float>(10, 0.0));
std::vector<float> v1D(100, 0.0);
for (int i = 0; i < 100; ++i)
v1D.push_back(i);
for (unsigned int j = 0; j < 10; j++)
{
std::copy(v1D.begin() + j * 10, v1D.begin() + (j + 1) * 10, std::back_inserter(v2D[j].begin()));
}
}
Would you please help solve this proplem? Thank you.

std::back_inserter takes a container, not an iterator. Change std::back_inserter(v2D[j].begin()) to std::back_inserter(v2D[j]). Note that this will be calling .push_back() on the std::vector<float> at v2D[j], so you probably also want to change std::vector< std::vector<float> > v2D(10, std::vector<float>(10, 0.0)); to std::vector< std::vector<float> > v2D(10);.
Alternatively, you can change std::back_inserter(v2D[j].begin()) to v2D[j].begin(). This works because std::copy wants an output iterator, and std::vector<>::iterator behaves as one when there are a sufficient number of elements in the vector<> to overwrite. And this way, your current initialization of v2D is already ideal.
EDIT: Someone else said this in a separate answer then deleted it, so I'll say it on their behalf because it's definitely noteworthy: because you initialize v1D with 100 elements, the [1..100] digits you then push_back are appended to the initial 100 elements (which all have your specified value of 0) rather than overwriting them. You should change std::vector<float> v1D(100, 0.0); to std::vector<float> v1D; to get the behavior you apparently want (or std::vector<float> v1D; v1D.reserve(100); if you're really being pedantic about efficiency).

Related

Create 2D vector from 2 1D vectors

I am fairly new to vectors and I'm trying to populate a 2D vector from 2 1D vectors for coordinate points. I have 2 vectors like this where source_x and source_y contains values from a file:
std::vector<float,T<float>> pos_x(5);
std::vector<float,T<float>> pos_y(5);
for (int i = 0; i < 5 ; i++){
pos_x[i] = i+1; //{1,2,3,4,5}
}
for (int i = 0; i < num ; i++){
pos_y[i] = i+1 ; //{1,2,3,4,5}
}
I created my 2D vector like this:
std::vector<std::vector<float, T<float>>> position;
for (int i = 0; i < num ; i++){
for (int j = 0; j < num ; i++){
//Output expected: {{1,2,3,4,5},{1,2,3,4,5}}
position[i][j] = //I'm confuse here
}
}
I am not certain how to populate pos_x to position[i] and pos_y to position[j].
Thank you
So my guess is this
std::vector<std::vector<float>> position(num, std::vector<float>(2));
for (int i = 0; i < num ; i++){
position[i][0] = pos_x[i];
position[i][1] = pos_y[i];
}
But I could easily be wrong.
UPDATE based on the example in the question I now think this is the correct code
std::vector<std::vector<float>> position(2, std::vector<float>(num));
for (int i = 0; i < num ; i++){
position[0][i] = pos_x[i];
position[1][i] = pos_y[i];
}
There's no such thing as a 2D vector. The truth is that you can create a vector that contains vectors. The first vector is used as an index in the collected vectors.
Note that this concept is similar to a 2D array: arr[3][4] means 3 indices, each one points to 4 data.
To create such 2D vector:
std::vector< std::vector <float>> positions.
Notice I didn't use the second parameter (as in std::vector<float, SomeAllocator> because we don't need this custom memory allocator.
Also notice that, contrary to arrays, I did't tell anything about the sizes of each vector, because the std::vector will take care of it.
Let's populate it.
The "main" vector contains vectors. So these secondary vectors may be created before stored in the "main" one.
std::vector<float> v1; //secondary
positions.push_back(v1); //add it to main vector
Put some values in the secondary:
v1.push_back(7.5);
v1.push_back(-3.1);
Another way is to access through the main vector. If we new this main vector contains v1 in its first index:
positions[0].push_back(8.); // same as v1.push_back(8.) if positions[0] refers to v1
or better using "at": positions.at(0).push_back(8.);
Change some value:
v1.at(1) = 66.88;
or
positions[0].at(1) = 66.88;
You can also do v1[1] = 66.88 but prefer the at() methof because it will check that index "1" is allowed by the size of the vector v1.
You can create and add another secondary vector:
std::vector<float> v2; //secondary
positions.push_back(v2); //add it to main vector
and work with it the same as with previous v1. Now, positions[1] refers to v2
I leave the rest of pulling from other vectors to you.

How to convert vector<Mat> to vector<float>?

Suppose i have a vector<Mat> called regionFeaMatand regionFeaMat.size() == 81 .In other words, regionFeaMat have 81 equal size matrix, and regionFeaMat[0].rows==256 and regionFeaMat[0].cols==1. I want to convert reginFeaMat to vector<float> reginFeaVec. I tried with following code but i got wrong result:
vector<float> regionFeaVec;
regionFeaVec.assign((float*)regionFeaMat[0].datastart, (float*)regionFeaMat[80].dataend);
You seem to have made a few wrong assumptions.
std::vector does store its elements contiguously in memory, but cv::Mat is a header containing a pointer to its internal buffer, so only pointers in vector<Mat> are stored contiguously, not the Mat data itself. Because of that, the memory that lies in between (float*)regionFeaMat[0].dataend and (float*)regionFeaMat[80].datastart is some random garbage - if it does contain other Mat's data partially, it's pure luck.
Because of the above, you can't have a one-liner assigning vector to any other vector and you have to insert each mat separately instead. Try something like this:
// prevent vector reallocation after each Mat insertion:
regionFeaVec.reserve(regionFeaMat.size()*regionFeaMat[0].cols*regionFeaMat[0].rows);
for (int i = 0; i < regionFeaMat.size(); ++i)
{
if (regionFeaMat[i].isContinuous())
regionFeaVec.insert(
regionFeaVec.end(),
(float*)regionFeaMat[i].datastart,
(float*)regionFeaMat[i].dataend
);
else
{
for (int j = 0; j < regionFeaMat[i].rows; ++j)
{
const float* row = regionFeaMat[i].ptr<float>(j);
regionFeaVec.insert(regionFeaVec.end(), row, row + regionFeaMat[i].cols);
}
}
}
Note that I'm checking if a particular Mat object is continuous, because as per OpenCV docs, each row may contain gaps at the end in some cases, and in that case we have to read the matrix row by row.
This code can be simplified, because if matrix is continuous, we may treat it as a 1D vector as per the docs referenced above:
// prevent vector reallocation after each Mat insertion:
regionFeaVec.reserve(regionFeaMat.size()*regionFeaMat[0].cols*regionFeaMat[0].rows);
for (int i = 0; i < regionFeaMat.size(); ++i)
{
cv::Size size = regionFeaMat[i].size();
if (regionFeaMat[i].isContinuous())
{
size.width *= size.height;
size.height = 1;
}
for (int j = 0; j < size.height; ++j)
{
const float* row = regionFeaMat[i].ptr<float>(j);
regionFeaVec.insert(regionFeaVec.end(), row, row + size.width);
}
}
If you want to prevent vector reallocation in more general cases, you also have to change the method of calculating the number of elements passed to reserve(). The method I use assumes all the Mat objects have only two dimensions that are equal for all the objects since this is how you described your problem.
Also, if you want to assign it to vector<float>, be sure that the element type of regionFeaMat is CV_32F.

Copy y-components of a vector

I want to copy the y-components of a vector of the type: std::vector <glm::vec3> example because I can't access only the y-components of this vector by doing something like example.size().y.... So, I assume I have to copy the content of the y-components to another another vector/array, but is there a way to do that? I was thinking of something like:
std::vector <int> something;
for (int i = 0; i < example.size(); i++)
{
something[i] = example[i].y;
}
but it doesn't work apparently.
Thanks!
You need to make sure the size of the vector grows along with the elements you push into them. The [] operator is only an accessor.
std::vector <int> something;
something.resize(example.size());
for (int i = 0; i < example.size(); i++)
{
something[i] = example[i].y;
}
std::vector <int> something;
for (int i = 0; i < example.size(); i++)
{
something[i] = example[i].y;
}
Two issues:
glm::vec3 is a floating-point type, and example[i].y is going to return a floating point value. And if these are normalized model vertices, they're very likely all in the range [-1,1], which means that something[i] would always be assigned -1, 0, or 1.
something never has its memory initialized in the code snippet you're providing. That will cause runtime crashes. You should be writing something like
std::vector<float> something(example.size());

How to initialize an empty global vector in C++

I have a general question. Hopefully, one of you has a good approach to solve my problem. How can I initialize an empty vector?
As far as I read, one has to know the size of an array at compiling time, though for vectors it is different. Vectors are stored in the heap (e.g. here: std::vector versus std::array in C++)
In my program I want to let the client decide how accurate interpolation is going to be done. That's why I want to use vectors.
The problem is: For reasons of clear arrangement I want to write two methods:
one method for calculating the coefficients of an vector and
one method which is providing the coefficients to other functions.
Thus, I want to declare my vector as global and empty like
vector<vector<double>> vector1;
vector<vector<double>> vector2;
However, in the method where I determine the coefficients I cannot use
//vector containing coefficients for interpolation
/*vector<vector<double>>*/ vector1 (4, vector<double>(nn - 1));
for (int ii = 0; ii < nn - 1; ii++) {vector1[ii][0] = ...;
}
"nn" will be given by the client when running the program. So my question is how can I initialize an empty vector? Any ideas are appreciated!
Note please, if I call another function which by its definition gives back a vector as a return value I can write
vector2= OneClass.OneMethod(SomeInputVector);
where OneClass is an object of a class and OneMethod is a method in the class OneClass.
Note also, when I remove the comment /**/ in front of the vector, it is not global any more and throws me an error when trying to get access to the coefficients.
Use resize:
vector1.resize(4, vector<double>(nn - 1));
Use resize() function as follows:
vector<vector<double>> v;
int f(int nn){
v.resize(4);
for(int i = 0; i < 4; i++){
v[i].resize(nn - 1);
}
}
It look to me that you're actually asking how to add items to your global vector. If so this might help:
//vector containing coefficients for interpolation
for (int i = 0; i < 4; ++i)
vector1.push_back(vector<double>(nn - 1));
for (int ii = 0; ii < nn - 1; ii++)
{
vector1[ii][0] = ...;
}
Unsure if it is what you want, but assign could be interesting :
vector<vector<double>> vector1; // initialises an empty vector
// later in the code :
vector<double> v(nn -1, 0.); // creates a local vector of size 100 initialized with 0.
vector1.assign(4, v); // vector1 is now a vector of 4 vectors of 100 double (currently all 0.)

C++ Using 3D Dynamic Arrays and Vectors

I'm new to C++ and getting a bit frustrated with it. Below, in pixelsVector, I am storing each pixel RGB float-value in Pixel and want to dump
all the values to a byte array with pixelsArray so I can output to an image file. HEIGHT and WIDTH refer to the image dimensions. The code below works fine, but I need to specify
the sizes of pixelsArray at run-time, because it may not always be a 500x500 image.
// WIDTH and HEIGHT specified at run-time
vector<vector<Pixel>> pixelsVector (WIDTH, vector<Pixel> (HEIGHT));
...
unsigned char pixelsArray[500][500][3];
for (int i = 0; i < 500; i++)
{
for (int j = 0; j < 500; j++)
{
// Returns RGB components
vector<float> pixelColors = pixelArray[i][j].getColor();
for (int k = 0; k < 3; k++)
{
pixels[i][j][k] = pixelColors.at(k);
}
}
}
// write to image file
fwrite(pixelsArray, 1, 500*500*3, file);
If I put HEIGHT and WIDTH instead of 500 and 500 above, I get an error since they are not constant values. Now using a 3D vector does seem to work, but fwrite won't take a vector for its first argument. I tried using a triple-pointer array but
it doesn't seem to work at all - maybe I was using it wrong. Here it is using a 3D vector for pixelsArray:
vector<vector<Pixel>> pixelsVector (WIDTH, vector<Pixel> (HEIGHT));
...
vector< vector< vector<unsigned char> > > pixelsArray;
for (int i = 0; i < HEIGHT; i++)
{
pixels.push_back(vector< vector<unsigned char> >());
for (int j = 0; j < WIDTH; j++)
{
pixels[i].push_back(vector<unsigned char>());
vector<float> pixelColors;
pixelColors = pixelArray[i][j].getColor();
for (int k = 0; k < 3; k++)
{
pixels[i][j][k] = pixelColors.at(k);
}
}
}
// Error
fwrite(pixelsArray, 1, 500*500*3, file);
Suggestions?
You could use Boost.MultiArray insead of vectors of vectors, which lets you access he underlying memory with the .data() method.
It looks like you are trying to manipulate images, so you might want to consider using Boost.Gil.
From the last code snippet:
vector<vector<Pixel>> pixelsVector (WIDTH, vector<Pixel> (HEIGHT));
Using uppercase names for variables you risk name collisions with macros. In C++ all uppercase names are conventionally reserved for macros.
...
vector< vector< vector<unsigned char> > > pixelsArray;
Presumably this vector is the same as is called pixels below?
If so, then the standard advice is that it helps to post real code.
Anyway, in order to output those bytes in one efficient operation you need the bytes to be contiguously stored in memory. So a vector of vectors of vectors is out. Use a single vector (C++ guarantees contiguous storage for the buffer of a std::vector).
for (int i = 0; i < HEIGHT; i++)
{
pixels.push_back(vector< vector<unsigned char> >());
for (int j = 0; j < WIDTH; j++)
{
pixels[i].push_back(vector<unsigned char>());
At this point you have an inner vector but it's empty, size 0.
vector<float> pixelColors;
pixelColors = pixelArray[i][j].getColor();
Presumably pixelArray is an instance of a class you have defined?
for (int k = 0; k < 3; k++)
{
pixels[i][j][k] = pixelColors.at(k);
}
Here you're trying to assign to non-existent elements of the empty innermost vector. You can either size it properly in advance, or use the push_back method for each value.
In addition, are you sure that the float values are integers in range 0 through 255 (or more generally, 0 through UCHAR_MAX) and not, say, in the range 0 through 1?
Perhaps you need to scale those values.
}
}
// Error
fwrite(pixelsArray, 1, 500*500*3, file);
If pixelsArray had been a (non-empty) vector of bytes, then you could use &pixelsArray[0] to obtain a pointer to the first byte.
Now, I know, the above only dissects some of what's wrong, and doesn't tell you directly what's right. :-)
But some more information would be needed to give example code for doing this, like (1) what are your float values, and (2) what do you want in your file?
Anyway, hope this helps,
– Alf