Sort matrix by scheme - c++

I need to sort negative elements of matrix by scheme below. I've tried to sort from another corner, but it is not working too. I think, that I need to put elems of matrix in 1d array. It should be sorted in Cocktail sort, but sort's type not my main problem.
My code:
int main() {
const int n = 4, m = 4;
int t, v[n*m], arr[n][m], i, j, tmp, lt, rt;
lt = 0;
rt = t;
srand(time(NULL));
for (i = 0; i < n; i++) {
for(j=0; j < m; j++) {
arr[i][j] = rand() % 100 - 50;
}
cout << endl;
}
t = 0;
for (i = 0; i < n; i++) {
for(j = 0; j < m; j++) {
if (arr[i][j] < 0) {
v[t] = arr[i][j];
t++;
}
}
}
while(lt <= rt) {
for (i = rt; i >= lt; i--) {
if(v[i] > v[i-1]) {
swap(v[i], v[i-1]);
}
}
lt++;
for (i = lt; i <=rt; i++) {
if(v[i] > v[i-1]) {
swap(v[i], v[i-1]);
}
}
rt--;
}
for (i = 0; i < t; i++) {
cout << v[i] << " ";
}
int r = 0;
for (i = 0; i < n; i++) {
for(j = 0; j < m; j++) {
if(arr[i][j] < 0) {
arr[i][j] = v[r];
r++;
}
}
}
}

The question sounds easy, but it is not. There is a lot of “indirection” in it, where you need to work with indices instead of values.
I shortly checked you code. It is mostly C–Code (not C++) and buggy.
Example:
int t;
rt = t;
With that you have an uninitialized variable, used as an array index. That is a fatal bug. You are also using VLA’s (Variable Length Array). This is not allowed in C++. And you are using plain C-Style arrays. This you should not do. Use std::vector, which can grow dynamically or at least std::array instead. And please give your variable more meaningful names.
I will show you one (out of the many possible) solutions, but I will use C++.
The core of the problem at hand is to find the row and column indices of the elements in the given matrix. That is not easy.
But ok, let’s start with that. If you draw a picture with the matrix and then add dotted lines over the diagonals, then you see the indices.
If the dimension of the matrix is dim then there are always dim + dim – 1 diagonals. The diagonals have first a rising number of elements and after hitting the main, longest diagonal in the middle, decreasing number of elements. So we iterate over the number of all diagonals, split by the middle diagonal, and calculate the corresponding row and column indices. This is a bit tricky, but after some time you will find out.
The resulting row and column indices will be stored in a struct. All diagonals with all row and column indices will be stored in a vector of struct. Additionally, we add the values of the original matrix cells.
Regarding the sorting. It is obviously your task to develop an own sorting algorithm. For that purpose, I created a function yourSort where you can put in your own algorithm. I simply use standard algorithms (std::sort). You may replace std::sort by your own function.
In main I put some driver code. First, we create a matrix and fill it with random values. Then we calculate the row and column indices. The entries with the negative values will be extracted and sorted. Then we copy the result back to the original matrix.
As said above, not so easy, because of the indirection with the indices and the constraint to use only negative numbers.
But anyway. Please see:
#include <iostream>
#include <vector>
#include <utility>
#include <random>
#include <algorithm>
#include <iterator>
#include <iomanip>
// Create types that are easy to understand
using RowIndex = size_t;
using ColumnIndex = size_t;
// Here we store the position (row and column) and the value of one cell in the matrix
struct PositionAndValue {
// Constructors
PositionAndValue() {};
PositionAndValue(const RowIndex r, const ColumnIndex c, const int v) : rowIndex(r), columnIndex(c), value(v) {};
// Data
RowIndex rowIndex{};
ColumnIndex columnIndex{};
int value{};
};
// Main data types
using Columns = std::vector<int>;
using Matrix = std::vector<Columns>;
using Diagonal = std::vector<PositionAndValue>;
// Fill matrix with random values. Standard function
void fillMatrixRandom(Matrix& m) {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(-50, 50);
std::for_each(m.begin(), m.end(), [&](Columns &c) {std::for_each(c.begin(), c.end(), [&](int &j) { j = dis(gen);}); });
}
// Calculate the indices for all diagonals
Diagonal calculateDiagonalIndices(const Matrix& matrix) {
// The return value
Diagonal diagonalIndices{};
// Matrix dimension
const size_t MatrixDimension{ matrix.size() };
// Overall number of diagonals for this matrix
const size_t NumberOfDiagonals{ MatrixDimension + MatrixDimension - 1 };
// index of middle (longest) diagonal
const size_t MiddleDiagonal { NumberOfDiagonals / 2 + 1 };
// Counter for element index in one specific diagonal
size_t elementInDiagonal{ 0 };
for (size_t diagonalIndex = 1; diagonalIndex <= NumberOfDiagonals; ++diagonalIndex) {
// If we are above the middle diagonal
if (diagonalIndex <= MiddleDiagonal) {
// Number of elements in diagonal will increase
++elementInDiagonal;
for (size_t j = 0; j < elementInDiagonal; ++j) {
// Calculate row and column and add to result
const RowIndex row{ j };
const ColumnIndex col{ diagonalIndex - j - 1 };
diagonalIndices.emplace_back(PositionAndValue(row, col, matrix[row][col]));
}
}
else {
// We are below the middle diagonal
// Number of elements in diagonal will decrease
--elementInDiagonal;
for (size_t j = 0; j < elementInDiagonal; ++j) {
// Calculate row and column and add to result
const RowIndex row{ diagonalIndex + j - MatrixDimension };
const ColumnIndex col{ MatrixDimension - j - 1 };
diagonalIndices.emplace_back(PositionAndValue(row, col, matrix[row][col]));
}
}
}
return diagonalIndices;
}
// Simple sorting function using std algorithms
template <typename T, typename ValueType>
void yourSort(std::vector<T>& vec, ValueType T::* mPtr) {
// We will extract the negative values
std::vector<ValueType> vt{};
// Extract
std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [&](const T & s) {return s.*mPtr; });
// Sort. ***** Please put here your sorting function
std::sort(vt.begin(), vt.end());
// Put back
std::for_each(vec.begin(), vec.end(), [&, i = 0U](T& s) mutable{s.*mPtr = vt[i++]; });
}
// Driver code
int main() {
// Lets use a matrix of this size
constexpr size_t MatrixDimension = 4U;
// Small lambda for printing a matrix
auto printMatrix = [](const Matrix & m) {std::for_each(m.begin(), m.end(), [](const Columns & c) {
for (int i : c) std::cout << std::setw(4) << i; std::cout << "\n"; }); std::cout << "\n"; };
// Define a matrix and fill it with random values
Matrix matrix(MatrixDimension, Columns(MatrixDimension));
fillMatrixRandom(matrix);
printMatrix(matrix);
// Calulate the indices on the diagonals
Diagonal diagonal{ calculateDiagonalIndices(matrix) };
// Extract the negatives
Diagonal negativesOnDiagonal{};
std::copy_if(diagonal.begin(), diagonal.end(), std::back_inserter(negativesOnDiagonal),
[](const PositionAndValue & pv) { return pv.value < 0; });
// Sort
yourSort(negativesOnDiagonal, &PositionAndValue::value);
// Copy back
std::for_each(negativesOnDiagonal.begin(), negativesOnDiagonal.end(),
[&matrix](const PositionAndValue & pv) { matrix[pv.rowIndex][pv.columnIndex] = pv.value; });
printMatrix(matrix);
return 0;
}

Related

Sorting columns of a matrix according to a particular row in c++

Is there a simple way to sort matrix in c++ according to eg. first row, so that all elements rearrange accordingly?
Example:
int matrix[3][3] = { {5,2,4},
{1,7,8},
{9,2,6} };
After sorting by first row it would look like this:
{2,4,5},
{7,8,1},
{2,6,9}
Preferably, I'd like to use sort() function, and I don't mind using vectors if it would make the task easier.
As the comments said, it's easier to sort a matrix by a column than by a row, since std::sort with the use of a lambda function will do the job for the former.
My recommendation is to sort the column indices by the row, then use the sorted indices to rebuild the matrix:
#include <algorithm>
using namespace std;
const int n = 3; // size of matrix
int sort_by_row = 0; // row to sort by
int original[n][n] = { {5,2,4},
{1,7,8},
{9,2,6} };
int main() {
int col_indices[n];
for (int i = 0; i < n; i++) col_indices[i] = i; // create column indices 0...n-1
sort(col_indices, col_indices + n, [] (const int &a, const int &b) { // sort indices by row
return original[sort_by_row][a] < original[sort_by_row][b];
});
int sorted[n][n]; // rebuild matrix
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
sorted[i][j] = original[i][col_indices[j]];
}
}
}
In this method, you iterate over the matrix once only, whereas if you transpose the matrix, sort, then transpose it back, you iterate over the matrix twice (during transposition).

C++ Sparse Matrix Class

I have faced this C++ problem:
In numerical analysis and scientific computing, a sparse matrix or sparse array is a matrix in which most of the elements are zero. There is no strict definition how many elements need to be zero for a matrix to be considered sparse but a common criterion is that the number of non-zero elements is roughly the number of rows or columns. By contrast, if most of the elements are nonzero, then the matrix is considered dense. The number of zero-valued elements divided by the total number of elements (e.g., m × n for an m × n matrix) is sometimes referred to as the sparsity of the matrix.
Write a class for storing a sparse matrix. Your class should support matrix sizes up to 1million x 1million.
Your class should be able to do any of the following:
A. Generate a random sparse matrix
B. Have the ability for an input matrix to be specified by a programmer
C. Compute the sparsity of a matrix
D. Rotate the matrix
I did research on the matter. I found this approach:
A proper way to create a matrix in c++
but I a doubt this would work because the shear size requirement (1M x 1M) in the problem.
Another approach I found using maps:
What is the best way to create a sparse array in C++?
but it is not quite what I need and I am unsure whether the (1M x 1M) requirement is met. Not sure how to approach part B as well. Also the the map is not encapsulated in the class.
I am interested in learning how to do this. This is not a school project or anything. This was an interview question that I failed to find the answer for.
Edit: Here's my implementation. Although I need to improve on it as it crashes right now if I specify a matrix size of 1Mx1M. I need to make it store only non-zero values.
Your feedback on the implementation is appreciated.
HEADER:
#ifndef SPARSEMATRIX_H
#define SPARSEMATRIX_H
#include <map>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
class SparseMatrix
{
public:
// Default constructor
SparseMatrix(unsigned int r, unsigned int c);
// Constructor that takes a 2D vector
SparseMatrix(std::vector<std::vector<int>> matrix);
// Deconstructor
~SparseMatrix();
// Print all matrix elements on console
void printMatrix();
// Return the sparsity
float computeSparsity();
// Rotate matrix by 90 degrees clockwise
void rotate90Clockwise();
// Return the element at the specified indices
int at(unsigned int rIndex, unsigned int cIndex);
private:
// Number of rows for the matrix
unsigned int rows;
// Number of columns for the matrix
unsigned int cols;
// Holds the number of zero-value elements in matrix
unsigned int zeroCounter;
// Map to hold the matrix in key-value fashion
std::map<std::string,int> data;
};
#endif // SPARSEMATRIX_H
SOURCE:
#include "sparsematrix.h"
#define MAX_SIZE (unsigned int) 1000000
#define MIN_SIZE (unsigned int) 1
SparseMatrix::SparseMatrix( unsigned int r, unsigned int c )
{
// Acquire the size required for the matrix
rows = r;
cols = c;
zeroCounter = 0;
// Check if the desired matrix is within design limit (1Mx1M elements)
if( rows > MAX_SIZE || rows < MIN_SIZE || cols > MAX_SIZE || cols < MIN_SIZE )
throw std::out_of_range("Matrix is out of range");
// Loop to generate random values and store in map
for( unsigned int i = 0; i < rows; ++i )
{
for( unsigned int j = 0; j < cols; ++j )
{
std::string key = std::to_string(i) + "," + std::to_string(j);
// Generate random value
unsigned int value = rand() % 10;
// Keep count of zero value elements
if( value == 0 ) zeroCounter++;
// Store value in map
data[key] = value;
}
}
}
SparseMatrix::SparseMatrix(std::vector<std::vector<int> > matrix)
{
unsigned int colNum = 0;
// Compute max column length
for (unsigned int i = 0; i < matrix.size(); ++i)
{
colNum = std::max( { colNum, matrix[i].size() } );
}
// Loop to transfer the elements from vector to map
// Fill all non existent elements with zero value
for (unsigned int i = 0; i < matrix.size(); ++i)
{
for (unsigned int j = 0; j < colNum; ++j)
{
std::string key = std::to_string(i) + "," + std::to_string(j);
unsigned int value;
if( j < matrix[i].size() )
{
// Element exists
value = matrix[i][j];
}
else
{
// Element does not exist; fill with zero
value = 0;
}
// Keep count of zero value elements
if( value == 0 ) zeroCounter++;
// Store value in map
data[key] = value;
}
}
}
SparseMatrix::~SparseMatrix()
{
// Matrix deconstructor
}
void SparseMatrix::printMatrix()
{
// Print all matrix elements on console
for(auto elem : data)
{
std::cout << elem.first << " " << elem.second << std::endl;
}
std::cout << " " << std::endl;
}
float SparseMatrix::computeSparsity()
{
// Return the calculated sparsity
return ((float)zeroCounter/(rows*cols));
}
void SparseMatrix::rotate90Clockwise()
{
std::map<std::string,int> temp;
std::string oldKey;
std::string newKey;
//Transpose matrix first
for(unsigned int r = 0; r < rows; r++)
{
for(unsigned int c = r; c < cols; c++)
{
oldKey = std::to_string(r) + "," + std::to_string(c);
newKey = std::to_string(c) + "," + std::to_string(r);
temp[newKey] = data[oldKey];
if( oldKey != newKey && data.count(newKey))
temp[oldKey] = data[newKey];
}
}
// Assign the temp map to our data map
data = temp;
// Matrix is transposed now so rows and cols should be swaped
std::swap(rows, cols);
// Reverse elements of matrix on row order
for(unsigned int r = 0; r < rows; r++)
{
for(unsigned int c =0; c < cols/2; c++)
{
oldKey = std::to_string(r) + "," + std::to_string(c);
newKey = std::to_string(r) + "," + std::to_string(cols-c-1);
data[newKey] = temp[oldKey];
if( oldKey != newKey && temp.count(newKey))
data[oldKey] = temp[newKey];
}
}
}
int SparseMatrix::at(unsigned int rIndex, unsigned int cIndex)
{
// Check if the requested element is within matrix range
if( rIndex >= rows || cIndex >= cols )
throw std::out_of_range("Indices out of range");
// Construct key for the requested element
std::string key = std::to_string(rIndex) + "," + std::to_string(cIndex);
// Return element at key
return data[key];
}

How to add a column to a multi-dimesional vector (C++)?

This might be easy but I just cant find a solution. I created a 2D vector like this:
vector<vector<int> > matrix;
vector<int> row;
for (int i = 0; i < x;i++) {
row.push_back(i);
}
for (int i = 0; i < x; i++) {
matrix.push_back(row);
}
The problem I have is that I now wanna add rows and columns as I need them because I might run out of matrix space over time but I don't know how to do it. The rows are easy I can just .push_back another row to the bottom end of the matrix...but I have no Idea how to add another column.
I'm sorry if this question is super stupid but I'm not that experienced in programming yet and I couldn't find anything on the particular problem of adding columns to a 2D vector.
Adding to your code, the idea is to loop over each row in the matrix and push a new element onto each vector. Together, all of these elements are a new column.
#include <iostream>
#include <vector>
using namespace std;
int main() {
// Initialize a 3x3 matrix
vector<vector<int>> matrix;
vector<int> row;
int x = 3;
for (int i = 0; i < x; i++) {
row.push_back(i);
}
for (int i = 0; i < x; i++) {
matrix.push_back(row);
}
// Add a column; the matrix is now 3x4
int newElement = 3;
for (auto &row : matrix) {
row.push_back(newElement);
}
// Print the matrix
for (auto &row : matrix) {
for (auto &cell : row) {
cout << cell << ' ';
}
cout << endl;
}
return 0;
}
You'll likely want to separate this code into functions.
vector<vector<T>> is a BAD way to implement a matrix. Well - it may not be a bad backend implementation, but its a bad public API.
I'd suggest using some library designed to support a Matrix. A few come to mind:
https://github.com/SophistSolutions/Stroika/blob/V2.1-Release/Library/Sources/Stroika/Foundation/Math/LinearAlgebra/Matrix.h
https://docs.opencv.org/3.4/d3/d63/classcv_1_1Mat.html
http://arma.sourceforge.net/docs.html#part_classes
or write your own and implement the basic functions directly.
Here is a simple function that will add a column to your matrix at a specified position:
void add_column(std::vector<std::vector<int>>& matrix,
const std::vector<int>& column, std::size_t position)
{
if(matrix.size() < position || position < 0) return; // check for position correctness
std::size_t index = 0;
for(auto& row : matrix){
row.insert(row.begin() + position, column[index++]);
}
}
For example, given a matrix:
std::vector<std::vector<int>> matrix;
and initializing it like so:
std::vector<int> column;
for (int i = 0; i < 3; i++) {
column.push_back(3);
}
for (int i = 0; i < 3; i++) {
matrix.push_back(column);
}
you end with with 3x3 matrix of 3s. Now, adding a column in between the first and the second one:
add_column(matrix, std::vector<int>({9, 9, 9}), 1);
and printing it:
for (auto& row : matrix) {
for (const auto x : row) {
std::cout << x << ' ';
}
std::cout << std::endl;
}
You end up with:
3 9 3 3
3 9 3 3
3 9 3 3

Way to replace one vector with another

I'm sorting 2 vectors using a vector of index.
the 2 vectors have not the same size. One vector (keys) is size X and the other (descriptors) is size X*128 (one key is parametrized by 128 values).
In order to create the vector of index, I generated a vector of unsigned, and used the iota function to put in this vector [0,1,2,...,X]
then I use the sort function to sort these index depending scale of a key (keys[i].s).
After that, I generate another vector in which I copy the values using the vector of index for both descriptors and keys (calling them descriptors_tmp, and keys_tmp), and then I want to make the first keys vector equal to the keys_tmp, and the same for descriptors equals to descriptors_tmp.
My question are :
-Is there a way to make that without making any copy. Since I don't need the previous version of keys and descriptors, I could just make the vector point on the other vector (something like *keys = *keys_tmp) ?
-Is there an easier way to achieve what I'm trying to achieve?
My code :
void _siftMatch::getIdxOfSorting(std::vector<unsigned>& idx_scale_order)
{
//keys[i].s is the scale and I sort depending decreasing scale
auto cmp_scale = [this](int i, int j) {
return keys[i].s > keys[j].s;
};
std::sort(idx_scale_order.begin(), idx_scale_order.end(), cmp_scale);
}
void _siftMatch::sort() {
//vector containing the index of sorted
std::vector<unsigned>idx_scale_order;
idx_scale_order.resize(keys.size());
//Generate [0,1,...,X]
std::iota(idx_scale_order.begin(), idx_scale_order.end(), 0);
//Sort the vector
getIdxOfSorting(idx_scale_order);
std::vector<float> descriptors_tmp;
std::vector<SiftGPU::SiftKeypoint> keys_tmp;
for (int i = 0; i < idx_scale_order.size(); ++i) {
keys_tmp.push_back(keys[idx_scale_order[i]]);
for (int j = 0; j < 128; ++j)
descriptors_tmp.push_back(descriptors[idx_scale_order[i] * 128 + j]);
}
//This is here that I want to put descriptors_tmp and keys_tmp in descriptors and keys
//descriptors.swap(descriptors_tmp.data);
}
Is there a way to make that without making any copy
This example of sorting 3 arrays according to one of the arrays, using a 4th generated array of indices that are sorted according to one of the 3 arrays may help. The key part of this is the in place reordering of all 4 arrays according to the array of indices. You'll need to modify this for your situation. I'm not sure why you are converting the array of indices to an array of numeric strings (via the itoa calls), using the indices directly works better for the example in this answer.
// sort 3 vectors according to one of them
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
int main()
{
std::vector <int> A; // ages
std::vector <std::string> N; // names
std::vector <int> Z; // zip codes
std::vector <size_t> I; // indices
int tA;
std::string tN;
int tZ;
A.push_back(37);
N.push_back("Ted");
Z.push_back(54211);
A.push_back(21);
N.push_back("John");
Z.push_back(53421);
A.push_back(31);
N.push_back("Fred");
Z.push_back(52422);
A.push_back(21);
N.push_back("Sam");
Z.push_back(51422);
// display the vectors
for(size_t i = 0; i < A.size(); i++)
std::cout << std::setw(6) << N[i]
<< std::setw(8) << Z[i]
<< std::setw(4) << A[i] << std::endl;
std::cout << std::endl;
// initialize the vector of indices
for(size_t i = 0; i < A.size(); i++)
I.push_back(i);
// sort I according to A
std::stable_sort(I.begin(), I.end(),
[&A](size_t i, size_t j) {return
A[i] < A[j];});
// reorder A, N, Z in place also restore I
// time complexity is O(n)
for(size_t i = 0; i < A.size(); i++){
size_t j, k;
if(i != I[i]){
tA = A[i];
tN = N[i];
tZ = Z[i];
k = i;
while(i != (j = I[k])){
A[k] = A[j];
N[k] = N[j];
Z[k] = Z[j];
I[k] = k;
k = j;
}
A[k] = tA;
N[k] = tN;
Z[k] = tZ;
I[k] = k;
}
}
// display the sorted vectors
for(size_t i = 0; i < A.size(); i++)
std::cout << std::setw(6) << N[i]
<< std::setw(8) << Z[i]
<< std::setw(4) << A[i] << std::endl;
return 0;
}

Apply same function over different dimensions of an multiple dimension vector

First, I'm sorry, I don't know a lot of c++, maybe my question is kind of stupid.
I have a multidimensional vector M. I want to be able to apply the same function either along the elements of a row i, or along the elements of a column j. I don't want to write the same function twice. It is possibly to do this in a rather simple way, like some overloading or with virtual iterators? can anyone write a simple example? thank you.
You can define you own iterator over the columns, so that you can use standard algorithms (like for_each, or transform as mentionned in another answer) to apply you function either to rows or columns of you array by just changing the iterators:
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
// Custom iterator to iterate over columns
// to be adapted to the underlying storage
class ColIterator : public std::iterator<std::forward_iterator_tag, double>
{
public:
typedef std::vector<std::vector<double> > MDarray;
ColIterator(MDarray & array, int i, int j) : array_(array), i_(i), j_(j) {}
ColIterator(const ColIterator& it) : array_(it.array_), i_(it.i_), j_(it.j_) {}
ColIterator& operator++() {
++i_;
return *this;
}
ColIterator operator++(int) {
ColIterator tmp(*this);
operator++();
return tmp;
}
bool operator==(const ColIterator& rhs) { return &array_==&rhs.array_ && i_==rhs.i_ && j_==rhs.j_; }
bool operator!=(const ColIterator& rhs) { return !operator==(rhs); }
double& operator*() {return array_[i_][j_];}
private:
MDarray & array_;
int i_;
int j_;
};
// a function
void mult2 (double & x) {
x *= 2;
}
int main () {
typedef std::vector<double>::iterator RowIterator;
int nRows = 5;
int nCols = 5;
ColIterator::MDarray array (nRows, std::vector<double>(nCols, 1));
// Apply function mult2 to column 3
int col = 3;
ColIterator beginCol (array, 0, col);
ColIterator endCol (array, nRows, col);
std::for_each(beginCol, endCol, mult2);
// Apply function mult2 to row 4
int row = 4;
RowIterator beginRow (array[row].begin());
RowIterator endRow (array[row].end());
std::for_each(beginRow, endRow, mult2);
// Check results
for (int i=0 ; i<nRows ; ++i) {
for (int j=0 ; j<nCols ; ++j) {
std::cout << " " << array[i][j];
}
std::cout << std::endl;
}
return 0;
}
A good way to go about this would be to use std::transform. Consult this link for more details. Short example with how to do this for rows is below. The column part is a little tricky.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int nRowCnt = 3, nColCnt = 3;
int RowFunc(int i) { return ++i; }
int ColFunc(int i) { return --i; }
void PrintArray(vector<vector<int>>& vecArray, int nRowCnt, int nColCnt)
{
for (int nOuter = 0; nOuter < nRowCnt; nOuter++)
{
for (int nInner = 0; nInner < nColCnt; nInner++)
{
cout<<vecArray[nOuter][nInner]<<" ";
}
cout<<endl;
}
}
int main()
{
vector< vector<int> > vecVals(nRowCnt, vector<int>(nColCnt,0));
vector< int > rowOut(nColCnt*nRowCnt,0), colOut(nColCnt*nRowCnt,0);
vector<int>::iterator itrOut;
for (int nRow = 0; nRow < nRowCnt; nRow++)
{
for (int nCol = 0; nCol < nColCnt; nCol++)
{
vecVals[nRow][nCol] = nRow * (10+nCol) ;
}
}
PrintArray(vecVals,nRowCnt,nColCnt);
itrOut = rowOut.begin();
for (int nOuter = 0; nOuter < nRowCnt; nOuter++)
{
std::transform(vecVals[nOuter].begin(),vecVals[nOuter].end(),itrOut,RowFunc);
itrOut += nColCnt;
}
itrOut = colOut.begin();
for (int nOuter = 0; nOuter < nRowCnt; nOuter++)
{
for (int nInner = 0; nInner < nColCnt; nInner++)
{
std::transform( vecVals[nInner].begin() + nOuter, vecVals[nInner].begin() + nOuter +1, itrOut,ColFunc);
itrOut++;
}
}
cout<<endl<<"Row Transformed"<<endl;
for (itrOut = rowOut.begin(); itrOut != rowOut.end(); itrOut++)
cout<<*itrOut<<" ";
cout<<endl<<"Col Transformed"<<endl;
for (itrOut = colOut.begin(); itrOut != colOut.end(); itrOut++)
cout<<*itrOut<<" ";
cout<<endl;
return 0;
}
There is a catch though, the column part won't work for non-square 2D arrays (i.e for it to work row and column counts must be the same). I guess this can be worked around with a little more thought.
If your multidimensional vector is an actual multidimensional vector, for example something like std::vector<std::vector<int>>, which isn't suggested, then you will have to write your own iterator. It's not very complicated. Boost.Iterator has concepts that can be used to help implement it.
If your multidimensional vector is a single vector with it's size set to the product of the dimensions (i.e. width * height), which is the preferred way to handle this, then it's much easier. It can be done with the utilities provided by Boost.Range.
Here's a quick and dirty example of using Boost.Range. It could be made a little prettier with decltype. If your compiler doesn't support C++11 (specifically auto), I wouldn't suggest using this, because the code becomes very hard to read.
template<typename T>
boost::iterator_range<typename T::iterator>
GetRow(T& vec, typename T::size_type row, typename T::size_type w,
typename T::size_type h) {
return boost::make_iterator_range(
vec.begin() + (row * w),
vec.begin() + ((row + 1) * w)
);
}
template<typename T>
boost::strided_range<boost::iterator_range<typename T::iterator>>
GetColumn(T& vec, typename T::size_type col, typename T::size_type w,
typename T::size_type h) {
boost::iterator_range<typename T::iterator> range = boost::make_iterator_range(
vec.begin() + col,
vec.begin() + col + (h - 1) * w + 1
);
return boost::strided_range<boost::iterator_range<typename T::iterator>>(w, range);
}
And then using these functions is pretty easy, though again, it can become very ugly if your compiler doesn't support auto.
const size_t WIDTH = 3;
const size_t HEIGHT = 3;
std::vector<int> vec(WIDTH * HEIGHT);
// Fill the first row with 1.
auto row = GetRow(vec, 0, WIDTH, HEIGHT);
for (auto it = row.begin(); it != row.end(); ++it) {
(*it) = 1;
}
// Fill the second column with 2.
auto col = GetColumn(vec, 1, WIDTH, HEIGHT);
for (auto it = col.begin(); it != col.end(); ++it) {
(*it) = 2;
}
// Contents of vec is:
// 1 2 1
// 0 2 0
// 0 2 0
You may also want to look into Boost.MultiArray, which is a library intended for things like this. It provides the functionality you want, but it's definitely not the friendliest library.
For a 2D vector:
Rows will be straightforward:
const std::vector<int>& getRow( const std::vector<std::vector<int>>& input, int rowIdx )
{
return input.at( rowIdx );
}
Columns a little trickier:
std::vector<int> getColumn( const std::vector<std::vector<int>>& input, int colIdx )
{
std::vector<int> output;
for ( unsigned i = 0; i < input.size(); ++i )
output.push_back( input.at( i ).at( colIdx ) );
return output;
}
These functions basically take a 2D integer vector and return a row/column vector based on the specified index.
This is the basis for what you're trying to do (from what I can gather). Minor modification will allow you to apply a function to rows/columns selectively instead of merely returning them.