简体   繁体   English

push_back / append或在C ++ Armadillo中追加带循环的向量

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

I would like to create a vector (arma::uvec) of integers - I do not ex ante know the size of the vector. 我想创建一个整数的向量(arma :: uvec) - 我不知道向量的大小。 I could not find approptiate function in Armadillo documentation, but moreover I was not successfull with creating the vector by a loop. 我在Armadillo文档中找不到合适的函数,但是我还没有成功通过循环创建向量。 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. 错误消息是: 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. 我不想将1分配给向量的第一个元素,但如果需要可以使用它。

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. PS:我真的想知道如何通过附加来获得未知长度的向量,这样我甚至可以在更一般的情况下使用它。

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. 将向量的大小设置为操作的理论最大长度(在本例中为nn ),然后使用循环设置向量中的某些值。 You will need to keep a separate counter for the number of set elements in the vector so far. 到目前为止,您需要为向量中的set元素数保留一个单独的计数器。 After the loop, take a subvector of the vector, using the .head() function. 循环之后,使用.head()函数获取向量的子向量。 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. 如果您仍然希望成为一个懒惰的编码器并且无效地附加元素,请使用.insert_rows()函数。

As a sidenote, your foo(arma::vec x) is already making an unnecessary copy the input vector. 作为旁注,你的foo(arma::vec x)已经在输入向量中进行了不必要的复制。 Arguments in C++ are by default passed by value , which basically means C++ will make a copy of x before running your function. 在C ++中的参数默认情况下通过值 ,这基本上意味着C ++将副本通过x上运行的功能之前。 To avoid this unnecessary copy, change your function to foo(const arma::vec& x) , which means take a constant reference to x . 要避免这种不必要的复制,请将函数更改为foo(const arma::vec& x) ,这意味着x 进行常量引用 The & is critical here. &在这里至关重要。

In addition to mtall's answer, which i agree with, for a case in which performance wasn't needed i used this: 除了mtall的答案,我同意,对于不需要性能的情况,我使用了这个:

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));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM