I worked out an algorithm that can be used recursively, which works in a non-recursive manner, however, I cannot test it in recursive form because I cannot create a n-1 dimensional variable from the template.For help I write down the variable names and its meaning:
v: the n-dimensional vector
dims: n long vector with every dimension (e.g: if it was an array looking like int x[3][6][4], then dims looks like: {3, 6, 4})
p: product of the dimensions, used to get the size of the flat vector (e.g: 3*6*4)
ret: the returned flat vector
sub_dims: same as dims execpt without the first dimension (e.g: {6, 4})
sub_p: same as p except without the first factor (e.g: 6*4)
sub_ret: the returned flat vector for the n-1 dimensional vector
the code:
template <typename T>
vector<int> dim_flat(vector<T> v, vector<int> dims)
{
// creating variables and vectors
int n = dims.size();
int p = dims[0];
for (int i = 1; i < n; i++)
{
p *= dims[i];
}
int sub_p = p / dims[0];
vector<int> sub_dims;
sub_dims.assign(dims.begin() + 1, dims.end());
vector<int> ret(p);
// algorithm
if (n > 1)
{
for (int i = 0; i < dims[0]; i++)
{
vector<int> sub_ret = dim_flat(v[i], sub_dims);
for (int j = 0; j < sub_p; j++)
{
ret[i * sub_p + j] = sub_ret[j];
}
}
}
else
{
// case for the input is 1D
// not yet written
}
return ret;
}
With this code the project build, however if I call it in main:
vector<int> ret = dim_flat(v, dims);
where v is e.g. an 4D vector and dims is a vector containing {3, 3, 3, 3}, then I get the following when trying to build:
error C2784: 'std::vector<_Ty> dim_flat(std::vector<T>,std::vector<_Ty>)' : could not deduce template argument for 'std::vector<T>' from 'int'
for the line
vector<int> sub_ret = dim_flat(v[i], sub_dims);
I kinda (but not really) understand the meaning of this error, so I expected the same to happen, which it did for this:
T x = v[i];
vector<int> sub_ret = dim_flat(x, sub_dims);
This is the part where I don't really understand the error anymore, because I thought that with the argument vector<T> v I specified that the input e.g. 4D vector will be understood as a vector of T where T is a 3D vector that can be also indexed since its a vector<T>. So following this logic I thought that if I give the recursion the first T being a 3D vector, then a step deeper this 3D vector will now be understood as a vector of T' where T' is a 2D vector, and so on.
Clearly either my logic is flawed, or I used the wrong method (, or both), so the question is: How can I solve / fix this?
EDIT:Credit to Max66 for the solution.
The code probably could be more optimized, but at least now it works.
Code:
//// for integer only
// case input is 0-dimensional (simply a variable)
template <typename T>
vector<int> dim_flat (const T &v, const vector<int> &dims)
{
return vector<int>(1, v);
}
// case input is n-dimensional
template <typename T>
vector<int> dim_flat(const vector<T> &v, const vector<int> &dims)
{
// creating variables and vectors
int n = dims.size();
int p = dims[0];
for (int i = 1; i < n; i++)
{
p *= dims[i];
}
int sub_p = p / dims[0];
vector<int> sub_dims;
sub_dims.assign(dims.begin() + 1, dims.end());
vector<int> ret(p);
// algorithm
if (n > 1) // case n-dimensional
{
for (int i = 0; i < dims[0]; i++)
{
vector<int> sub_ret = dim_flat(v[i], sub_dims);
for (int j = 0; j < sub_p; j++)
{
ret[i * sub_p + j] = sub_ret[j];
}
}
}
else // case 1-dimensional
{
for (int i = 0; i < p; i++)
{
vector<int> sub_ret = dim_flat(v[i], sub_dims);
ret[i] = sub_ret[0];
}
}
return ret;
}
Short answer: add the function
std::vector<int> dim_flat (int v, std::vector<int> const &)
{ return {v}; }
if you can use C++11 or newer, or
std::vector<int> dim_flat (int v, std::vector<int> const &)
{ return std::vector<int>(1, v); }
if you have to use C++98
Long answer: if I'm not wrong, the problem is that, when you call dim_flat() with an std::vector<int> (when T is int), you have n == 1, so dim_flat() isn't called (is executed the "case for the input 1D") but the compiler isn't so smart to understand that there is no need to call dim_flat() with int (instead std::vector<T>) so look for dim_flat(int, std::vector<int>) and doesn't find it.
So, to make the compiler happy, you have to implement dim_flat(int, std::vector<int>).
Can be a dummy function (that return an empty vector), but I suggest you to implement it correctly.
A little of topic: please, avoid unusefull copies of vectors; in your dim_flat(), v and dims are only readed, not modified; so you can receive they as const reference, as follows
template <typename T>
std::vector<int> dim_flat(std::vector<T> const & v,
std::vector<int> const & dims)
P.s.: why don't you simply write as follows ?
std::vector<int> dim_flat (std::vector<int> const & v)
{ return v; }
template <typename T>
std::vector<int> dim_flat(std::vector<std::vector<T>> const & v)
{
std::vector<int> ret;
for ( auto const & e : v )
{
auto s = dim_flat(e);
ret.reserve( ret.size() + s.size() );
ret.insert( ret.end(), s.cbegin(), s.cend() );
}
return ret;
}
Related
I am trying to construct a function take takes a vector, ranks it, sorts it and outputs the sorted and ranked vector with the original positioning of the values. For example: Input: [10,332,42,0.9,0] Output: [3, 5, 4, 2, 1]
I used this stack overflow question (specifically Marius' answer) as a reference guide, however I am stuck with my code now and do not understand where the issue is.
I am running a C++03.
One of the errors I get is
error: invalid types ‘const float*[float]’ for array subscript’ for array subscript on my if statement.
//Rank the values in a vector
std::vector<float> rankSort(const float *v_temp, size_t size)
{
vector <float> v_sort;
//create a new array with increasing values from 0 to n-1
for(unsigned i = 0; i < size; i++)
{
v_sort.push_back(i);
}
bool swapped = false;
do
{
for(unsigned i = 0; i < size; i++)
{
if(v_temp[v_sort[i]] > v_temp[v_sort[i+1]]) //error line
{
float temp = v_sort[i];
v_sort[i] = v_sort[i+1];
v_sort[i+1] = temp;
swapped = true;
}
}
}
while(swapped);
return v_sort;
}
std::vector<float> rankSort(const std::vector<float> &v_temp)
{
return rankSort(&v_temp[0], v_temp.size());
}
Your problem is a misconception on rankings. Array indices are of size_t not float, so you'll need to return a vector<size_t> not a vector<float>.
That said your sort is O(n2). If you're willing to use more memory we can get that time down to O(n log(n)):
vector<size_t> rankSort(const float* v_temp, const size_t size) {
vector<pair<float, size_t> > v_sort(size);
for (size_t i = 0U; i < size; ++i) {
v_sort[i] = make_pair(v_temp[i], i);
}
sort(v_sort.begin(), v_sort.end());
pair<double, size_t> rank;
vector<size_t> result(size);
for (size_t i = 0U; i < size; ++i) {
if (v_sort[i].first != rank.first) {
rank = make_pair(v_sort[i].first, i);
}
result[v_sort[i].second] = rank.second;
}
return result;
}
Live Example
EDIT:
Yeah this actually gets a little simpler when taking a vector<float> instead of a float[]:
vector<size_t> rankSort(const vector<float>& v_temp) {
vector<pair<float, size_t> > v_sort(v_temp.size());
for (size_t i = 0U; i < v_sort.size(); ++i) {
v_sort[i] = make_pair(v_temp[i], i);
}
sort(v_sort.begin(), v_sort.end());
pair<double, size_t> rank;
vector<size_t> result(v_temp.size());
for (size_t i = 0U; i < v_sort.size(); ++i) {
if (v_sort[i].first != rank.first) {
rank = make_pair(v_sort[i].first, i);
}
result[v_sort[i].second] = rank.second;
}
return result;
}
Live Example
//Rank the values in a vector
std::vector<size_t> rankSort(const std::vector<float> &v_temp)
{
vector <size_t> v_sort;
//create a new array with increasing values from 0 to size-1
for(size_t i = 0; i < v_temp.size(); i++)
v_sort.push_back(i);
bool swapped = false;
do
{
swapped = false; //it's important to reset swapped
for(size_t i = 0; i < v_temp.size()-1; i++) // size-2 should be the last, since it is compared to next element (size-1)
if(v_temp[v_sort[i]] > v_temp[v_sort[i+1]])
{
size_t temp = v_sort[i]; // we swap indexing array elements, not original array elements
v_sort[i] = v_sort[i+1];
v_sort[i+1] = temp;
swapped = true;
}
}
while(swapped);
return v_sort;
}
v_sort[i] is a float (it's just an element of v_sort vector) while only integral types can be used as array subscripts.
Probably you meant v_sort as an array of indices, thus, you should declare it as std::vector<size_t> or std::vector<int> something like that.
UP: Also, given that you change the values of the array passed, it's not an elegant way of pass it by const reference.
To sum up, the following code compiles correctly on my machine:
std::vector<unsigned> rankSort(float *v_temp, size_t size)
{
vector <unsigned> v_sort;
//create a new array with increasing values from 0 to n-1
for(unsigned i = 0; i < size; i++)
{
v_sort.push_back(i);
}
bool swapped = false;
do
{
for(unsigned i = 0; i < size; i++)
{
if(v_temp[v_sort[i]] > v_temp[v_sort[i+1]]) //error line
{
unsigned temp = v_sort[i];
v_sort[i] = v_sort[i+1];
v_sort[i+1] = temp;
swapped = true;
}
}
}
while(swapped);
return v_sort;
}
std::vector<unsigned> rankSort(std::vector<float> &v_temp)
{
return rankSort(&v_temp[0], v_temp.size());
}
I suggest you adopt a more robust solution by taking advantage of what you have in the STL. To do so, we will first make an "index vector", ie. a std::vector<std::size_t> vsuch that for any i, v[i] == i is true:
// I'm sure there's a more elegant solution to generate this vector
// But this will do
std::vector<std::size_t> make_index_vector(std::size_t n) {
std::vector<std::size_t> result(n, 0);
for (std::size_t i = 0; i < n; ++i) {
result[i] = i;
}
return result;
}
Now all we have to do is to sort this vector according to a specific comparison function that will use the input vector. Furthermore, to allow for the most generic approach we will give the user the opportunity to use any comparison functor:
template <typename T, typename A, typename Cmp>
struct idx_compare {
std::vector<T, A> const& v;
Cmp& cmp;
idx_compare(std::vector<T, A> const& vec, Cmp& comp) : v(vec), cmp(comp) {}
bool operator()(std::size_t i, std::size_t j) {
return cmp(v[i], v[j]);
}
};
template <typename T, typename A, typename Cmp>
std::vector<std::size_t> sorted_index_vector(std::vector<T, A> const& vec, Cmp comp) {
std::vector<std::size_t> index = make_index_vector(vec.size());
std::sort(index.begin(), index.end(),
idx_compare<T, A, Cmp>(vec, comp));
return index;
}
In the sorted index vector, index[0] is the index of the lowest value in the input vector, index[1] the second lowest and so on. Therefore, we need one additional step to get the rank vector from this one:
std::vector<std::size_t> get_rank_vector(std::vector<std::size_t> const& index) {
std::vector<std::size_t> rank(index.size());
for (std::size_t i = 0; i < index.size(); ++i) {
// We add 1 since you want your rank to start at 1 instead of 0
// Just remove it if you want 0-based ranks
rank[index[i]] = i + 1;
}
return rank;
}
Now we combine all the pieces together:
template <typename T, typename A, typename Cmp>
std::vector<std::size_t> make_rank_vector(
std::vector<T, A> const& vec, Cmp comp) {
return get_rank_vector(sorted_index_vector(vec, comp));
}
// I had to stop using default template parameters since early gcc version did not support it (4.3.6)
// So I simply made another overload to handle the basic usage.
template <typename T, typename A>
std::vector<std::size_t> make_rank_vector(
std::vector<T, A> const& vec) {
return make_rank_vector(vec, std::less<T>());
}
Result with [10, 332, 42, 0.9, 0]: [3, 5, 4, 2, 1].
You can find a Live Demo on gcc 4.3.6 to explicit this behavior.
Here is my codes using STL to achieve this in a concise way to get the rank.
template <typename T>
vector<size_t> calRank(const vector<T> & var) {
vector<size_t> result(var.size(),0);
//sorted index
vector<size_t> indx(var.size());
iota(indx.begin(),indx.end(),0);
sort(indx.begin(),indx.end(),[&var](int i1, int i2){return var[i1]<var[i2];});
//return ranking
for(size_t iter=0;iter<var.size();++iter){
result[indx[iter]]=iter+1;
}
return result;
}
I have a function to flatten out an vector of vectors to a single vector. Comming from c# i would write it something like:
vector<T> flatten(vector<vector<T>> 2dVector)
{
vector<T> newVector(2dVector.size()*2dVector[0].size())
for (int i = 0; i < 2dVector.size(); i++)
{
for (int j = 0; j < 2dVector[i].size(); j++)
{
newVector[j + i * 2dVector.size()] = 2dVector[i][j];
}
}
return newVector;
}
but this code gives 20+ errors in msvc++
After hours of seaching the web for how to make this function, i modified the method signature to
utilities.h:
template <typename A, typename B> A flatten(const B 2dVector&);
utilities.cpp:
template <typename A, typename B> A flatten(const B 2dVector&)
{
A newVector(2dVector.size()*2dVector[0].size())
for (int i = 0; i < 2dVector.size(); i++)
{
for (int j = 0; j < 2dVector[i].size(); j++)
{
newVector[j + i * 2dVector.size()] = 2dVector[i][j];
}
}
return newVector;
}
But i still get on the order of ~15 errors from this code, and i am all out of ideas. Any suggestions?
Your code contains several problems. To name a few:
An identifier cannot start with a number.
Your template should be parameterized by a single parameter - the basic value type of the returned vector
Your code internally assumes that the vectors are same-sized, where it is just as easy to accommodate a ragged array
There are more efficient ways to append a vector to the end of a vector.
I'd suggest the following alternative:
#include <vector>
template<typename T>
std::vector<T> flatten(const std::vector<std::vector<T>> &orig)
{
std::vector<T> ret;
for(const auto &v: orig)
ret.insert(ret.end(), v.begin(), v.end());
return ret;
}
int main()
{
std::vector<std::vector<int>> vv;
vv.push_back(std::vector<int>{1, 2, 3});
vv.push_back(std::vector<int>{10, 20});
flatten(vv);
}
How can I pass an array, declared in main method by reference as a parameter to a function? Also the compiler wants dimentions, but when i give them with variables, the compiler gives errors of invalid integer dimensions of the array, here's the code:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int scanV(int Row, int value, int M, int (&tableValues)[])
{
for (int i = 0; i <= M; ++i)
{
if (tableValues[Row - 1][i] == 1)
{
if (i + value <= M)
{
tableValues[Row][i+value] == 1;
}
if (i - value >= 0)
{
tableValues[Row][i-value] = 1;
}
}
}
}
int main()
{
int C, B, M;
cin>>C;
int integers[C];
for (int i = 1; i < C; ++i)
{
cin>>integers[i];
}
cin>>B;
cin>>M;
integers[0] = B;
int tableValues[C][M + 1];
tableValues[0][B] = 1;
for (int i = 1; i < C; ++i)
{
scanV(i, integers[i], M, tableValues);
}
return 0;
}
One simple solution is to use vectors. Consider this simple example:
#include <iostream>
#include <vector>
void f (std::vector<std::vector<int> > &v)
{
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
v[i][j] = i * 3 + j;
}
int main()
{
std::vector<std::vector<int> > v (3, std::vector<int> (3, 0));
f (v);
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
std::cout << v[i][j] << ' ';
}
In main, a 2D vector of ints (3x3) is created. The constructor shows 3 elements, all initialized with a vector of ints, which are in turn created with 3 elements initialized to 0.
Then, the vector is passed by reference to the function f, which assigns increasing values. When the vector is printed in main, it shows:
0 1 2 3 4 5 6 7 8
As you can see, their use is very similar to normal arrays, but they are actually contained, and provide easy access to a new level of programming using the STL.
In C++11, their use becomes even more familiar. You can assign vectors as follows:
std::vector<int> v0 = {2, 5};
std::vector<std::vector<int> > v1 { {1,2,3} , {4,5,6} , {7,8,9} };
Note that for vectors of multiple dimensions it's a good idea to encapsulate it in a matrix class of some sort with an underlying 1D vector type instead.
Edit:
Here's an example of initializing a 1D and 2D vector to specified elements. As seen above, this is easy in C++11, but if you have an array already, it's still pretty quick.
int a [5] = {1,2,3,4,5}; //normal
std::vector<int> v1 (a, a +5); //create using beginning and ending addresses of a
int b[3][3] = { {1,2,3} , {4,5,6} , {7,8,9} }; //normal
std::vector<std::vector<int> > v2; //empty vector
for (int i = 0; i < 3; ++i) //3 in first dimension
v2.push_back (std::vector<int> (b [i], b [i] + 3)); //push a vector with the appropriate 3 elements of b onto the back of v2
For going through one element at a time, you can do this:
std::vector<std::vector<int> > v (3, std::vector<int> (3));
for (int i = 0; i < v.size(); ++i) //v.size() == 3
for (int j = 0; j < v [i].size(); ++j)
adjustElement (v [i][j]); //replace with what you need
std::vectors are the way to go in C++ as variable-length arrays (such as int integers[C];) are forbidden.
I recommend typedefing these to make your code easier to read:
#include <vector>
typedef std::vector<int> row_t;
typedef std::vector<row_t> table_t;
Then you can declare:
void scanV(int Row, int value, int M, table_t& tableValues)
I've made this void since it doesn't return anything.
Your variables in int main() then become:
row_t integers;
table_t tableValues;
Watch out for this line:
tableValues[Row][i+value] == 1;
You probably meant to assign, rather than to check equivalence!
And please try to pick some more meaningful variable names than B, M, C...
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.
I've a 2d array, say A[2][3]={{1,2,3},{4,5,6}}; and I want to push it into a 2D vector(vector of vectors). I know you can use two for loops to push the elements one by on on to the first vector and then push that into the another vector which makes it 2d vector but I was wondering if there is any way in C++ to do this in a single loop. For example I want to do something like this:
myvector.pushback(A[1]+3); // where 3 is the size or number of columns in the array.
I understand this is not a correct code but I put this just for understanding purpose. Thanks
The new C++0x standard defines initializer_lists which allows you to:
vector<vector<int>> myvector = {{1,2,3},{4,5,6}};
gcc 4.3+ and some other compilers have partial C++0x support.
for gcc 4.3+ you could enable c++0x support by adding the flag -std=c++0x
Its not the best way to have your static data represented like that. However, if your compiler vendor supports C++ tr1 then you could do:
#include <tr1/array> // or #include <array>
...
typedef vector<vector<int> > vector2d;
vector2d myvector;
// initialize the vectors
myvector.push_back(vector<int>());
myvector.push_back(vector<int>());
typedef std::array<std::array<int, 3>, 2> array2d;
array2d array = {{1,2,3},{4,5,6}};
array2d::const_iterator ai = array.begin(), ae = array.end();
for (vector2d::iterator i = myvector.begin(), e = myvector.end()
; i != e && ai != ae
; i++, a++)
{
// reserve vector space
i->reserve(array.size());
// copy array content to vector
std::copy(ai.begin(), ai->end(), i->begin());
}
You can use vector::assign (pointers to array elements are valid iterators):
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
std::vector<std::vector<int> > v(2);
for (size_t i = 0; i < 2; ++i)
v[i].assign(a[i], a[i] + 3);
This is a little tricky, but you could use template recursion to help you in having the assignment done almost completely at compile-time. I understand that's not exactly what you are looking for, but I think it's worthwhile :-)
Here's the code:
#include <vector>
using namespace std;
typedef vector<vector<int> > vector2d;
template<size_t K, size_t M, size_t N>
struct v_copy {
static void copy(vector2d& v, int(&a)[M][N])
{
v[K - 1].assign(a[K - 1], a[K - 1] + N);
v_copy<K - 1, M, N>::copy(v, a);
}
};
template<size_t M, size_t N>
struct v_copy<1, M, N> {
static void copy(vector2d& v, int(&a)[M][N])
{
v[0].assign(a[0], a[0] + N);
}
};
template<size_t M, size_t N>
void copy_2d(vector2d& v, int(&a)[M][N])
{
v_copy<M, M, N>::copy(v, a);
}
int main()
{
int A[2][3] = {{0, 1, 2}, {10, 11, 12}};
vector2d vector(2);
copy_2d(vector, A);
}
it needed a struct because in C++ you can't do partial specialization of functions. BTW , compiling it with gcc version 4.5.0, this code produces the same assembly as
vector[1].assign(A[1], A[1] + 3);
vector[0].assign(A[0], A[0] + 3);
It should not be very hard to have it compile with different types of 2-dimensions arrays.
If you want to push the data into vector of vectors, you have to write something like this:
vector<int> inner;
vector< vector<int> >outer;
...
outer.pushback(inner);
I think there is no way to do it in a single loop.
If you want to use just one vector (something similar like you written), then you can do it in a single loop:
int A[2][3]={{1,2,3},{4,5,6}};
int* p = A[0];
std::vector<int> inner;
std::vector< std::vector<int> >outer;
for(int i = 0; i < 6; ++i)
{
inner.push_back(*p++);
}
It's kind of cheating, but you could take advantage of the vector constructor to do one of the loops for you:
#include <vector>
int main() {
const int XMAX = 2, YMAX = 3;
int A[XMAX][YMAX] = {{1,2,3}, {4,5,6}};
std::vector<std::vector<int> > v;
for (size_t x = 0; x < XMAX; ++x) {
v.push_back(std::vector<int>(&A[x][0], &A[x][YMAX]));
}
}
You can resize vectors and then use copy.
int A[2][3]={{1,2,3},{4,5,6}};
std::vector< std::vector<int> > vec;
vec.resize(2);
for (int i=0; i<2; i++)
{
vec[i].resize(3);
std::copy(A[i], A[i]+3, vec[i].begin());
}
Is it practical? Definetly not.
Hm... I can produce a partial answer but not a full one.
int elementCount = 6; // I wonder if this can be done somehow with sizeof(A) * sizeof(A[0])
int* end = A + elementCount;
for(int* current = A; current < end; ++current) {
myvector.pushback(*current);
}
No. The only thing you can do is leverage existing loop functions so that you only have to write one or zero of your own loops.