Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rcpp Copy a vector to a vector

I am new to Rcpp and C++ coding in general, so forgive me for asking basic questions. The cpp part of the code is

// test.cpp

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
void testRun() {
   IntegerVector Grp1 = IntegerVector::create(1,2,3,4);
   IntegerVector Grp2 = IntegerVector::create(3,4,5,6);

   Rf_PrintValue(Grp1);
   Grp1 = Grp2;
   Rf_PrintValue(Grp1);
   Grp2[3] = Grp2[3]+1;
   Rf_PrintValue(Grp1);
}

and when I run testrun(), I get the output

> Rcpp::sourceCpp('test.cpp')
> testRun()
[1] 1 2 3 4
[1] 3 4 5 6
[1] 3 4 5 7

When I assign Gr2 to Gr1 in Gr1 = Gr2, changing elements in Gr2 after the assignment changes the values in Gr1 as well. Is there a function for IntegerVectors that could do something like Gr1 = copy of Gr2 or should I be using a loop to do that.

Thanks a lot!

like image 646
Bong Avatar asked Feb 22 '15 23:02

Bong


People also ask

How do I copy a vector array to another?

Begin Initialize a vector v1 with its elements. Declare another vector v2 and copying elements of first vector to second vector using constructor method and they are deeply copied. Print the elements of v1. Print the elements of v2.

How do I move an element from one vector to another in C++?

You can't move elements from one vector to another the way you are thinking about; you will always have to erase the element positions from the first vector. If you want to change all the elements from the first vector into the second and vice versa you can use swap. @R.

How do you combine two vectors?

The simplest solution is to use a copy constructor to initialize the target vector with the copy of all the first vector elements. Then, call the vector::insert function to copy all elements of the second vector. We can also use only vector::insert to copy elements of both vectors into the destination vector.


Video Answer


2 Answers

As hinted in the comment, you could use

Grp1 = clone(Grp2) ;

but this will create a new R object that then get assigned to Grp1, so you pay for some memory allocation and you discard some memory that could have been used, i.e. more work for the garbage collector down the line.

You could also just reuse the existing memory from Grp1 with std::copy

std::copy( Grp2.begin(), Grp2.end(), Grp1.begin() ) ;

Another way that is perhaps over the top is to use sapply. Something like this:

auto identity = [](double x){ return x; } ;
Grp1 = sapply( Grp2, identity );

But given Rcpp does not sapply over lambdas, you'd probably have to define identity outside your function for this approach to be useable.

inline double identity(double x){ 
    return x ;
}

FWIW, in Rcpp14 or Rcpp11, you could simply do:

Grp1 = import(Grp2) ;
like image 169
Romain Francois Avatar answered Sep 28 '22 08:09

Romain Francois


What is currently happening is a very common error with pointers. Grp1 and Grp2 are pointers, so setting one equal to the other means that they point to the same array (and any changes to one array will affect the other). One solution would be to use a iterator to copy all values over one at a time. This would be done by emptying one IntegerVector by popping all values and then pushing all elements from the other IntegerVector into the emptied IntegerVector.

like image 32
David Avatar answered Sep 28 '22 10:09

David