push_back/append or appending a vector with a loop in C++ Armadillo

巧了我就是萌 提交于 2019-12-10 17:07:15

问题


I would like to create a vector (arma::uvec) of integers - I do not ex ante know the size of the vector. I could not find approptiate function in Armadillo documentation, but moreover I was not successfull with creating the vector by a loop. I think the issue is initializing the vector or in keeping track of its length.

 arma::uvec foo(arma::vec x){
 arma::uvec vect;
 int nn=x.size();
 vect(0)=1;
 int ind=0;
 for (int i=0; i<nn; i++){
     if ((x(i)>0)){
        ind=ind+1;
        vect(ind)=i;
     }
 }
   return vect;
}

The error message is: Error: Mat::operator(): index out of bounds.

I would not want to assign 1 to the first element of the vector, but could live with that if necessary.

PS: I would really like to know how to obtain the vector of unknown length by appending, so that I could use it even in more general cases.


回答1:


Repeatedly appending elements to a vector is a really bad idea from a performance point of view, as it can cause repeated memory reallocations and copies.

There are two main solutions to that.

  1. Set the size of the vector to the theoretical maximum length of your operation (nn in this case), and then use a loop to set some of the values in the vector. You will need to keep a separate counter for the number of set elements in the vector so far. After the loop, take a subvector of the vector, using the .head() function. The advantage here is that there will be only one copy.

  2. An alternative solution is to use two loops, to reduce memory usage. In the first loop work out the final length of the vector. Then set the size of the vector to the final length. In the second loop set the elements in the vector. Obviously using two loops is less efficient than one loop, but it's likely that this is still going to be much faster than appending.

If you still want to be a lazy coder and inefficiently append elements, use the .insert_rows() function.

As a sidenote, your foo(arma::vec x) is already making an unnecessary copy the input vector. Arguments in C++ are by default passed by value, which basically means C++ will make a copy of x before running your function. To avoid this unnecessary copy, change your function to foo(const arma::vec& x), which means take a constant reference to x. The & is critical here.




回答2:


In addition to mtall's answer, which i agree with, for a case in which performance wasn't needed i used this:

void uvec_push(arma::uvec & v, unsigned int value) {
    arma::uvec av(1);
    av.at(0) = value;
    v.insert_rows(v.n_rows, av.row(0));
}


来源:https://stackoverflow.com/questions/28247490/push-back-append-or-appending-a-vector-with-a-loop-in-c-armadillo

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!