Reputation: 780
I would like to implement a function that like the input of a 2d vector (a matrix), contain its origin elements, and return a reshaped version based on the input for number of columns and rows. The reshaped matrix need to be filled with all the elements of the original matrix in the same row-traversing order as they were.
I completed the following code:
vector<vector<int>> matrixReshape(vector<vector<int>>& nums, int r, int c) {
int r_old = nums.size();
int c_old = nums[0].size();
if(r*c != r_old*c_old) return nums;
vector<vector<int>> new_nums;
new_nums.resize(r);
// get the new matrix proper size
for (int i =0; i< r; i++){
new_nums[i].resize(c);
}
int c_curr =0;
int r_curr =0;
// assign element
for (int i = 0; i < r_old; i ++){
for (int j =0; j < c_old; j++){
if(c_curr == c){
r_curr++;
c_curr =0;
}
new_nums[r_curr][c_curr] = nums[i][j];
c_curr++;
}
}
return new_nums;
}
However, I feel like there must be a better way of doing it. I search stackoverflow and found several questions
How can I resize a 2D C++ vector?
How can I resize a 2D vector of objects given the width and height?
However, those answers all "reset" the current matrix which is not what I want. So my question is, is there a faster way to generate a 2d vector from a 2d vector by re-arranging its elements into the desired new shape?
Upvotes: 1
Views: 5563
Reputation: 33932
Decided to follow my comment through. This answer heads pretty far into X-Y territory, but it should simplify things a great deal
#include <iostream>
#include <iomanip>
#include <vector>
#include <exception>
// wrapping class for 2D matrixes
class Matrix
{
private:
size_t rows, columns; // large, unsigned datatype. Don't want negative
// indices, so why allow them?
std::vector<int> matrix; // 1D vector. Simple and easy to handle.
// also often much faster than vector of vectors
// due to improved spatial locality helping
// predictability of data access
public:
// catchable exception should user request impossible dimension transformation
class BadDimsException: public std::exception
{
public:
const char* what() const noexcept
{
return "Invalid dimensions specified";
}
};
// build zero-filled Matrix
Matrix(size_t numrows, size_t numcols) :
rows(numrows), columns(numcols), matrix(rows * columns)
{
}
// build Matrix based on another Matrix with convertable dimensions
// All of the heavy lifting is performed in the member initializer list
// by simply copying data store of source Matrix
// if matrix cannot be transformed, the thrown exception leaves user with
// nothing to work with and no chance of trying to continue with an un-
// transformed matrix
Matrix(size_t numrows, size_t numcols, const Matrix & source) :
rows(numrows), columns(numcols), matrix(source.matrix)
{
if (rows * columns != source.rows * source.columns)
{ // Bad dimensions. Blow up.
throw BadDimsException();
}
}
// 2D to 1D mapping accessor
int & operator()(size_t row, size_t column)
{
// check bounds here
return matrix[row * columns + column];
}
// 2D to 1D mapping accessor for constant Matrix
int operator()(size_t row, size_t column) const
{
// check bounds here
return matrix[row * columns + column];
}
// dimension accessors
size_t getRows() const
{
return rows;
}
size_t getColumns() const
{
return columns;
}
};
// stream formatter
std::ostream & operator<<(std::ostream & out, const Matrix & mat)
{
for (size_t row = 0; row < mat.getRows(); ++row)
{
for (size_t col = 0; col < mat.getColumns(); ++col)
{
std::cout << std::setw(5) << mat(row, col);
}
std::cout << '\n';
}
return out;
}
And to test/demonstrate usage:
int main()
{
Matrix one(2, 6); // make 2x6 matrix
int count = 0;
// set inputs to make errors really stand out
for (size_t row = 0; row < one.getRows(); ++row)
{
for (size_t col = 0; col < one.getColumns(); ++col)
{
one(row, col) = count++;
}
}
// print initial matrix
std::cout << one << '\n';
// make reshaped matrix
Matrix two(3,4, one);
//print reshaped Matrix
std::cout << two << '\n';
try
{
// make invalid reshaped matrix
Matrix three(3, 3, one);
// This should never print
std::cout << three << '\n';
}
catch (const Matrix::BadDimsException & bde)
{
// Yay! Caught error!
std::cout << bde.what() << '\n';
}
}
Upvotes: 1