Melissa Key
Melissa Key

Reputation: 4551

change vector element by name in rcpp

I have a function where I need to make a table (tab, then change one value - the value where tab.names() == k, where k is given in the function call.

Looking at http://dirk.eddelbuettel.com/code/rcpp/Rcpp-quickref.pdf, I've hoped that the following code would work (replacing "foo" with a variable name), but I guess that requires the element name to be static, and mine won't be. I've tried using which but that won't compile (invalid conversion from 'char' to 'Rcpp::traits::storage_type<16>::type {aka SEXPREC*}' - so I'm doing something wrong there.

#include <RcppArmadillo.h>
#include <algorithm>
//[[Rcpp::depends(RcppArmadillo)]]
using namespace Rcpp;

// [[Rcpp::export]]
IntegerVector fun(const arma::vec& assignment, int k) {

  // count number of peptides per protein
  IntegerVector tab = table(as<IntegerVector>(wrap(assignment)));
  CharacterVector all_proteins = tab.names(); 

  char kc = '0' + k;

  // what I need a working version of: 
  tab(kc) = 1;  // gets ignored, as does a [] version of the same thing.
  // or
  tab('0' + k) = 1; // also ignored

  int ki = which(all_proteins == kc); // gives me compile errors

  // extra credit
  // tab.names(k-1) = "-1";

  return tab;
}

/*** R
set.seed(23)
  x <- rpois(20, 5)
  k <- 5

  fun(x, k)

  # same thing in R:
  expected_output <- table(x)
  expected_output # before modification
#  x
#   3  4  5  6  7  9 10 12 
#   2  4  3  3  4  2  1  1 

  expected_output[as.character(k)] <- 1 # this is what I need help with
  expected_output

#  x
#   3  4  5  6  7  9 10 12 
#   2  4  1  3  4  2  1  1 

  # extra credit:
  names(expected_output)[as.character(k)] <- -1

*/

I'm still learning rcpp, and more importantly, still learning how to read the manual pages and plug in the right search terms into google/stackoverflow. I'm sure this is basic stuff (and I'm open to better methods - I currently think like an R programmer in terms of initial approaches to problems, not a C++ programmer.)

(BTW - The use of arma::vec is used in other parts of the code which I'm not showing for simplicity - I realize it's not useful here. I debated on switching it, but decided against it on the principle that I've tested that part, it works, and the last thing I want to do is introduce an extra bug...)

Thanks!

Upvotes: 1

Views: 344

Answers (2)

Ralf Stubner
Ralf Stubner

Reputation: 26833

You can use the .findName() method to get the relevant index:

#include <RcppArmadillo.h>
#include <algorithm>
//[[Rcpp::depends(RcppArmadillo)]]
using namespace Rcpp;

// [[Rcpp::export]]
IntegerVector fun(const arma::vec& assignment, int k) {

  // count number of peptides per protein
  IntegerVector tab = table(as<IntegerVector>(wrap(assignment)));
  CharacterVector all_proteins = tab.names(); 

  int index = tab.findName(std::string(1, '0' + k));

  tab(index) = 1;
  all_proteins(index) = "-1";
  tab.names() = all_proteins;

  return tab;
}

/*** R
set.seed(23)
x <- rpois(20, 5)
k <- 5

fun(x, k)
*/

Output:

> Rcpp::sourceCpp('table-name.cpp')

> set.seed(23)

> x <- rpois(20, 5)

> k <- 5

> fun(x, k)
 3  4 -1  6  7  9 10 12 
 2  4  1  3  4  2  1  1 

Upvotes: 2

F. Priv&#233;
F. Priv&#233;

Reputation: 11728

You could write your own function (use String instead of char):

int first_which_equal(const CharacterVector& x, String y) {

  int n = x.size();
  for (int i = 0; i < n; i++) {
    if (x[i] == y) return(i);
  }

  return -1;
}

Also, it seems that tab(kc) is converting kc to an integer representation.

Upvotes: 1

Related Questions