Push back data into a 2D vector - c++

I am trying to create a 2d vector of set size and then insert data into it. The issue I am having is being able to insert the data filling up each column and row in the 2d vector.
I have read through various other threads, but cannot find an implementation that works for me.
Here is some sample code for my issue:
int main()
{
vector<string> strVec = { "a","b","c","d" };
// letters to insert into vector
// this is just a sample case
vector< vector<string>> vec; // 2d vector
int cols = 2; // number of columns
int rows = 2; // number of rows
for (int j = 0; j < cols; j++) // inner vec
{
vector<string>temp; // create a temporary vec
for (int o = 0; o < rows; o++) // outer vec
{
temp.push_back("x"); // insert temporary value
}
vec.push_back(temp); // push back temp vec into 2d vec
}
// change each value in the 2d vector to one
// in the vector of strings
// (this doesn't work)
// it only changes the values to the last value of the
// vector of strings
for (auto &v : strVec)
{
for (int i = 0; i < vec.size(); i++)
{
for (int j = 0; j < vec[i].size(); j++)
{
vec[i][j] = v;
}
}
}
// print 2d vec
for (int i = 0; i < vec.size(); i++)
{
for (int j = 0; j < vec[i].size(); j++)
{
cout << vec[i][j];
}
cout << endl;
}
}

You are assigning same string to all elements of vec again and again in the loop for (auto &v : strVec).
That is, vec[0][0]=vec[0][1]=vec[1][0]=vec[1][1]=a, vec[0][0]=vec[0][1]=vec[1][0]=vec[1][1]=b, and so on.
Removing this outer loop and assigning strVec[i*cols+j] to vec[i][j], we can get desired output.
DEMO is here.
for (int i = 0; i < vec.size(); i++)
{
for (int j = 0; j < vec[i].size(); j++)
{
vec[i][j] = strVec[i*cols+j];
}
}

for (int i = 0; i < vec.size(); i++)
{
for (int j = 0; j < 2; j++)
{
cout << vec[i][j];
}
cout << endl;
}

Related

2d push_back doesnt save to vector values

I have a 2d vector which should save x and y coordinates. Everything works as intended except saving this values to vector. What did I do wrong?
void Game::GetShips(Board &b)
{
vector<vector<int>> shipCors;
for (int i = 0; i < BOARDSIZE; i++) {
for (int j = 0; j < BOARDSIZE; j++) {
if (b.getSpaceValue(i, j) == SHIP) {
cout << "X :"<< i<<"\n Y:"<<j<<'\n';
shipCors[i].push_back(j);
}
}
}
cout<< shipCors.size()<<'\n';
}
You declared an empty vector
vector<vector<int>> shipCors;
So you may not use the subscript operator
shipCors[i].push_back(j);
You could write
for (int i = 0; i < BOARDSIZE; i++) {
shipCors.resize( shipCors.size() + 1 );
for (int j = 0; j < BOARDSIZE; j++) {
if (b.getSpaceValue(i, j) == SHIP) {
cout << "X :"<< i<<"\n Y:"<<j<<'\n';
shipCors[i].push_back(j);
}
}
}
Pay attention to that as you are using the index i then you need to add a "row" of the vector even if the row will be empty after executing the inner for loop.
It will be even better to resize the vector initially before the for loops like
vector<vector<int>> shipCors;
shipCors.resize( BOARDSIZE );
for (int i = 0; i < BOARDSIZE; i++) {
for (int j = 0; j < BOARDSIZE; j++) {
if (b.getSpaceValue(i, j) == SHIP) {
cout << "X :"<< i<<"\n Y:"<<j<<'\n';
shipCors[i].push_back(j);
}
}
}
An alternative approach is to have a vector declared like
std::vector<std::pair<int, int>> shipCors;
In this case your loop will look like
for (int i = 0; i < BOARDSIZE; i++) {
for (int j = 0; j < BOARDSIZE; j++) {
if (b.getSpaceValue(i, j) == SHIP) {
cout << "X :"<< i<<"\n Y:"<<j<<'\n';
shipCors.emplace_back(i, j);
}
}
}
Or to keep the data sorted you can declare a set like
std::set<std::pair<int, int>> shipCors;

Armadillo altering entire columns instead of singular elements when attempting to copy from another matrix class

I am trying to copy a matrix from an old matrix class to an armadillo matrix. Unfortunately when attempting to do this with a for loop the armadillo matrix will copy the value from the old matrix to the ENTIRE column when the lowest-most element is non-zero (I am using sparse matrices). I have attached the code that is being used below. This is very simplified because I need to figure out why it is doing this first. According to the documentation this should work.
main()
{
OldMatrixClass MatrixA(size, size);
FillMatrix(MatrixA, size);
for (auto i = 0; i < size; i++)
{
for (auto j = 0; j < size; j++)
{
file << MatrixA[i][j] << "\t";
}
file << "\n";
}
arma::Mat<double> ArmaA(size, size);
ArmaA.zeros();
CopyMatrix(MatrixA, ArmaA, size);
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
file << ArmaA[i,j] << "\t";
}
file << "\n";
}
}
void FillMatrix(OldMatrixClass &A, int size)
{
double num = 0.15;
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
if (rand() % 101 < 26)
{
A[i][j] = num;
}
else
{
A[i][j] = 0;
}
}
}
}
void CopyMatrix(OldMatrixClass A, arma::Mat<double> &B, int size)
{
for (int k = 0; k < size; k++)
{
for (int j = 0; j < size; j++)
{
B[j, k] = A[j][k];
}
}
}
This is the output when I run this code... As you can see only the entire columns are altered if the last element in MatrixA column is non-zero.
Output
Is there something I'm doing wrong? Is my syntax messed up somewhere?
See the documentation:
Caveat: accessing elements via [i,j] and [i,j,k] does not work correctly in C++; instead use (i,j) and (i,j,k)

Matrix multiplication using 2d vector

Following is my code:
void matrix(int rowsInA, int columnsInA, int columnsInB){
std::vector< vector<int> > a;
std::vector< vector<int> > b;
for (int i = 0; i < rowsInA; i++) {
vector<int> myRow(1);
a.push_back(myRow);
for (int j = 0; j < columnsInA-1; j++) {
int x = rand() % 100;;
myRow.push_back(x);
}
}
for (int i = 0; i < rowsInA; i++) {
vector<int> myRow(1);
b.push_back(myRow);
for (int j = 0; j < columnsInB-1; j++) {
int x = rand() % 100;;
myRow.push_back(x);
}
}
std::vector< vector<int> > c = multiply(a, b);
for (int i = 0; i < rowsInA; i++) {
for (int j = 0; j < columnsInB; j++) {
cout << c[i][j];
}
}
}
std::vector< vector<int> > multiply(std::vector< vector<int> > a , std::vector< vector<int> > b) {
int rowsInA = 9;
int columnsInA = 9; // same as rows in B
int columnsInB = 9;
std::vector< vector<int> > d;
for (int i = 0; i < rowsInA; i++) {
for (int j = 0; j < columnsInB; j++) {
vector<int> myRow;
myRow.push_back(a[i][0]);
d.push_back(myRow);
for (int k = 0; k < columnsInA; k++) {
myRow.push_back(myRow[i]+ a[i][k] * b[k][j]);//error here
}
}
}
return d;
}
first function matrix() creates two vector within a vector and assigns random values to it and then call multiply in which vectors are multiplied.
It is giving vector subscript out of range error
Your code:
for (int i = 0; i < rowsInA; i++) {
vector<int> myRow(1);
a.push_back(myRow);
for (int j = 0; j < columnsInA-1; j++) {
int x = rand() % 100;;
myRow.push_back(x);
}
}
Constructs a single element vector, pushes it on to a, appends some
values to your temporary, and then throws it away. C++ is not Java or C#. The vector at the back of a is not changed by changes to myRow.
You also seem to be putting a fixed value as the first element of myRow, and
then appending randomness to it. Is that what you meant?
What you need is:
for (int i = 0; i < rowsInA; i++) {
vector<int> myRow;
myRow.reserve(columnsInA);
myRow.push_back(0); // First element fixed.
for (int j = 1; j < columnsInA; j++) {
const int x = rand() % 100;;
myRow.push_back(x);
}
a.push_back(myRow);
}
Alternatively, making all the values random, and working directly with the vector:
a.reserve(rowsInA);
for (int i = 0; i < rowsInA; i++) {
a.push_back( {} );
a.back().reserve(columnsInA);
for (int j = 0; j < columnsInA; j++) {
const int x = rand() % 100;;
a.back().push_back(x);
}
}
You have a similar problem with initializing B, and your multiply loop needs to accumulate a[i][k] * b[k][j] into a temporary sum, then push that onto myRow, and finally push myRow onto d.
Finally, when you have got this working, look up how to write a Matrix class that stores all the data in a vector with rows*cols elements and then uses an indexing function to refer to it. Your cache will thank you.

How do I copy the elements of a 2D array onto a 1D vector?

So i keep trying to transfer the elements but it keeps giving me repeated elements, it fails to properly copy the 2D array onto a 1D vector
// This was one of my attempts
vector<int> rando(int rowsize, int columnsize)
{
int elements = rowsize*columnsize;
vector<int> x(elements);
int matrix[100][100];
for(int i = 0; i < rowsize; i++)
{
for(int j = 0; j < columnsize; j++)
{
srand((int)time(0));
matrix[i][j]= -10 + rand() % 21;
for(int n=0; n < elements; n++)
x[n]=matrix[i][j];
}
// Ive also tried this
for(int n=0; n < elements; n++)
{
for(int i = 0; i < rowsize; i++)
{
for(int j = 0; j < columnsize; j++)
{
x[n]=matrix[i][j];
}
}
}
}
return x;
}
Why do you want to store data into the matrix first and copy it into the vector afterwards? Use the vector from the start.
std::vector<int> rando(std::size_t rowsize, std::size_t columnsize)
{
std::vector<int> v(rowsize*columnsize);
std::mt19937 mt{std::random_device{}()};
std::uniform_int_distribution<int> rand_dist(-10, 10);
for (auto & e : v) e = rand_dist(mt);
return v;
}
If you want to transfer data from a matrix into a vector you must calculate the proper index or just increment a single variable as Thomas Matthews suggests.
constexpr std::size_t n = 100, m = 100;
int matrix[n][m];
// do stuff with matrix
std::vector<int> v(n*m);
for (std::size_t i=0; i<n; ++i)
{
for (std::size_t j=0; j<m; ++j)
{
v[i*m + j] = matrix[i][j];
}
}
THe general copy should loop through the 2 dimensions, and just increment the target index at each iteration (no third nested loop):
int n=0;
for(int i = 0; i < rowsize; i++)
{
for(int j = 0; j < columnsize; j++)
{
...
x[n++]=matrix[i][j]; // not in an additional for loop !!
}
} // end of initialisation of matrix
If your matrix is a 2D array (i.e. contiguous elements) you can also take the following shortcut using <algorithm>:
copy (reinterpret_cast<int*>(matrix), reinterpret_cast<int*>(matrix)+elements, x.begin());
Try this:
unsigned int destination_index = 0;
for(int i = 0; i < rowsize; i++)
{
for(int j = 0; j < columnsize; j++)
{
x[destination_index++]=matrix[i][j];
}
}
The destination index is incremented after each assignment to a new slot.
No need for a 3rd loop.
It is enough to use two loops.
For example
srand((int)time(0));
for(int i = 0; i < rowsize; i++)
{
for(int j = 0; j < columnsize; j++)
{
matrix[i][j]= -10 + rand() % 21;
x[i * columnsize + j] = matrix[i][j];
}
}
In general if you have a two-dimensional array and want to copy nRows and nCols of each row elements in a vector then you can use standard algorithm std::copy declared in header <algorithm>
For example
auto it = x.begin();
for ( int i = 0; i < nRows; i++ )
{
it = std::copy( matrix[i], matrix[i] + nCols, it );
}

Memory issues with two dimensional array

Following this nice example I found, I was trying to create a function that dynamically generates a 2D grid (two dimensional array) of int values.
It works fairly well the first couple of times you change the values but if crashes after that. I guess the part where memory is freed doesn't work as it should.
void testApp::generate2DGrid() {
int i, j = 0;
// Delete previous 2D array
// (happens when previous value for cols and rows is 0)
if((numRowsPrev != 0) && (numColumnsPrev != 0)) {
for (i = 0; i < numRowsPrev; i++) {
delete [ ] Arr2D[i];
}
}
// Create a 2D array
Arr2D = new int * [numColumns];
for (i = 0; i < numColumns; i++) {
Arr2D[i] = new int[numRows];
}
// Assign a random values
for (i=0; i<numRows; i++) {
for (j = 0; j < numColumns; j++) {
Arr2D[i][j] = ofRandom(0, 10);
}
}
// Update previous value with new one
numRowsPrev = numRows;
numColumnsPrev = numColumns;
}
I see 1 major bug:
// Assign a random values
for (i=0; i<numRows; i++){
for (j=0; j<numColumns; j++){
Arr2D[i][j] = ofRandom(0, 10);
}
}
Here the variable 'i' is used as the first index into 'Arr2D' and goes to a max of (numRows -1)
While in this code:
for (i=0; i<numColumns; i++)
{
Arr2D[i] = new int[numRows];
}
The variable 'i' is used as the first index but goes to a max of (numColumns-1). If numRows is much larger than numColumns then we are going to have a problem.
As a side note. When you try and clean up you are leaking the columns:
if((numRowsPrev != 0) && (numColumnsPrev != 0))
{
for (i=0; i<numRowsPrev; i++){
delete [ ] Arr2D[i];
}
// Need to add this line:
delete [] Arr2D;
}
Next thing to note.
This is truly not a good idea. Use some of the provided STL classes (or potentially boost Matrix). This looks like you are binding global variables and all sorts of other nasty stuff.
2-dim array in C++ with no memory issues:
#include <vector>
typedef std::vector<int> Array;
typedef std::vector<Array> TwoDArray;
Usage:
TwoDArray Arr2D;
// Add rows
for (int i = 0; i < numRows; ++i) {
Arr2D.push_back(Array());
}
// Fill in test data
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numCols; j++) {
Arr2D[i].push_back(ofRandom(0, 10));
}
}
// Make sure the data is there
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numCols; j++) {
std::cout << Arr2D[i][j] << ' ';
}
std::cout << '\n';
}