2015-02-09 35 views
1

我想索引帶有名稱的矩陣。通常的方法給出了錯誤:爲矩陣命名的索引

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

我看了看在Matrix.h和矩陣單元測試中RCPP,但沒有找到類似的例子。此郵件列表question也未提供執行此操作的方法。

我可以寫我自己的代碼來索引矩陣,也許使用R的內部C interface

回答

1

這是絕不是一個強大的解決方案,但希望一個跳點,哪裏operator()超載處理,因爲行&列索引傳遞的intstring不同的組合:

#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 
*/ 
+0

謝謝!如果這符合rcpp庫的風格,我們應該將這些重載操作符添加到主存儲庫中。 – highBandWidth 2015-02-10 16:18:17

+0

不客氣,就像我說的那樣,這是一個非常小的起點,並且在它被認爲是健壯的之前需要更多的工作。例如,我不確定在C++中執行邊界檢查的正確/慣用方式是什麼,所以我只是(相當懶惰地)強迫出界字符串索引是一個有效(但不正確)的值(例如'else {另外,你肯定希望添加不僅僅是原子(double)的方法,而且還要添加列/行向量,因爲'Rcpp的各種'Matrix'類允許例如'x(1,Rcpp :: _)'(矩陣x的第二行向量)。 – nrussell 2015-02-10 16:26:18

+0

我當然認爲這將是一個有用的功能 - 它只需要更多的時間和精力,而且肯定需要由我的知識豐富的C++程序員來審查。 – nrussell 2015-02-10 16:29:19

1

我們只支持數字(行)索引。

您可以添加一個「names」屬性並查找其中的索引,和/或添加您自己的訪問器方法。