Reputation: 17296
I am trying to index a matrix with names. The usual method gives errors:
NumericMatrix mytest(NumericVector v) {
NumericMatrix ans(v.length(), v.length());
rownames(ans) = v;
float y = ans("1",0);
NumericVector x = ans.row("1");
return (ans);
}
I looked over in Matrix.h and the matrix unit tests in rcpp and couldn't find a similar example. Also this mailing list question didn't provide a method to do it.
Can I write my own code to index the matrix, perhaps using R's internal C interface?
Upvotes: 1
Views: 125
Reputation: 18612
This is by no means a robust solution, but hopefully a jumping off point for you, where operator()
is overloaded to handle different combinations of int
and string
passed as row & column indices:
#include <Rcpp.h>
// [[Rcpp::plugins(cpp11)]]
class MyMat : public Rcpp::NumericMatrix {
public:
MyMat(const Rcpp::NumericMatrix& data_,
const std::vector<std::string>& rnames_,
const std::vector<std::string>& cnames_)
: data(data_),
rnames(rnames_),
cnames(cnames_) {}
double operator()(const std::string& i, const std::string& j) {
typedef std::vector<std::string>::const_iterator cit;
cit it_i = std::find(rnames.begin(), rnames.end(), i);
cit it_j = std::find(cnames.begin(), cnames.end(), j);
int idx_i, idx_j;
if (it_i != rnames.end() ) {
idx_i = it_i - rnames.begin();
} else {
idx_i = rnames.size();
}
if (it_j != cnames.end() ) {
idx_j = it_j - cnames.begin();
} else {
idx_j = cnames.size();
}
return data(idx_i, idx_j);
}
double operator()(const std::string& i, const size_t j) {
typedef std::vector<std::string>::const_iterator cit;
cit it_i = std::find(rnames.begin(), rnames.end(), i);
int idx_i, idx_j;
if (it_i != rnames.end() ) {
idx_i = it_i - rnames.begin();
} else {
idx_i = rnames.size();
}
if (j <= cnames.size() ) {
idx_j = j;
} else {
idx_j = cnames.size();
}
return data(idx_i, idx_j);
}
double operator()(const size_t i, const std::string& j) {
typedef std::vector<std::string>::const_iterator cit;
cit it_j = std::find(cnames.begin(), cnames.end(), j);
int idx_i, idx_j;
if (i <= rnames.size() ) {
idx_i = i;
} else {
idx_i = rnames.size();
}
if (it_j != cnames.end() ) {
idx_j = it_j - cnames.begin();
} else {
idx_j = cnames.size();
}
return data(idx_i, idx_j);
}
double operator()(const int& i, const int& j) {
return data(i, j);
}
private:
Rcpp::NumericMatrix data;
std::vector<std::string> rnames;
std::vector<std::string> cnames;
};
// [[Rcpp::export]]
void test_MyMat(Rcpp::NumericMatrix m)
{
std::vector<std::string> rnames = { "a", "b", "c" };
std::vector<std::string> cnames = { "A", "B", "C" };
MyMat mmObj(m,rnames,cnames);
Rcpp::Rcout << "(Row 1, Column 1)" <<
std::endl;
Rcpp::Rcout << "(b,B) = " << mmObj("b","B") <<
std::endl << "(b,1) = " << mmObj("b",1) <<
std::endl << "(1,B) = " << mmObj(1,"B") <<
std::endl << "(1,1) = " << mmObj(1,1) <<
std::endl;
}
/*** R
x <- matrix(1:9,nrow=3)
test_MyMat(x)
#(Row 1, Column 1)
#(b,B) = 5
#(b,1) = 5
#(1,B) = 5
#(1,1) = 5
x[2,2]
#[1] 5
*/
Upvotes: 1
Reputation: 368389
We only support numeric (row) indices.
You could add a "names" attribute and look up the index in that, and/or add your own accessor methods.
Upvotes: 1