2016-07-12 2 views
1

최근에 버그가 있었는데 수정했을 때 요소 이름이 지정된 VECSXP (즉 R 목록 유형)를 반환 할 수 있는지 궁금했습니다. 이 C++ 코드 :R 확장자를 쓸 때 명명 된 VECSXP를 반환하는 방법

SEXP do_bla() 
{ 
    int prtCnt = 0; 
    SEXP a = PROTECT(allocMatrix(REALSXP, 5, 5)); 
    prtCnt++; 
    SEXP b = PROTECT(allocVector(REALSXP, 5)); 
    prtCnt++; 
    SEXP OS = PROTECT(allocVector(VECSXP, 2)); 
    prtCnt++; 
    SET_VECTOR_ELT(OS, 0, a); 
    SET_VECTOR_ELT(OS, 1, b); 
    UNPROTECT(prtCnt); 
    return OS; 
} 

R 나에게 두 가지 요소 (행렬과 벡터)의 목록을 제공합니다 :

s[[1]]; s[[2]] 

이 같은 색인을 생성 할 수 있습니다

s <- .Call("do_bla", ....) 

이를 가능하게하려면 무엇을 변경해야합니까?

s$a; s$b 

아니면 가능하지 않습니까?

답변

3

섹션의 5.9.4, Writing R Extensions을 참조하십시오. 이름의 벡터를 할당하고 채우고 목록에 names 속성을 설정하십시오.

library(inline) 
named <- cfunction(signature(), ' 
    /* allocate and populate list */ 
    SEXP OS = PROTECT(allocVector(VECSXP, 2)); 
    SET_VECTOR_ELT(OS, 0, allocMatrix(REALSXP, 5, 5)); 
    SET_VECTOR_ELT(OS, 1, allocVector(REALSXP, 5)); 

    /* create names */ 
    SEXP nms = PROTECT(allocVector(STRSXP, 2)); 
    SET_STRING_ELT(nms, 0, mkChar("foo")); 
    SET_STRING_ELT(nms, 1, mkChar("bar")); 

    /* assign names to list */ 
    setAttrib(OS, R_NamesSymbol, nms); 

    /* cleanup and return */ 
    UNPROTECT(2); 
    return OS;') 
3

R의 C API 함수를 사용하여이 작업을 수행 할 수있는 더 관용적 방법이있을 수 있습니다 - 그것은 안전하고 간결 나는이 Rcpp를 통해 C++와 막대기 경향 -하지만 추가 다음과 같은 작동합니다 :

SEXP n = PROTECT(Rf_allocVector(STRSXP, 2)); 
prtCnt++; 
SET_STRING_ELT(n, 0, Rf_mkChar("a")); 
SET_STRING_ELT(n, 1, Rf_mkChar("b")); 
Rf_setAttrib(OS, R_NamesSymbol, n); 

그러나 R의 C 코드와 함께 제공되는 상용구의 대부분을 제거 할 수 있으므로 Rcpp를 사용하는 것이 좋습니다.

#include <Rcpp.h> 

// [[Rcpp::export]] 
SEXP do_bla() { 
    int prtCnt = 0; 
    SEXP a = PROTECT(Rf_allocMatrix(REALSXP, 5, 5)); 
    prtCnt++; 
    SEXP b = PROTECT(Rf_allocVector(REALSXP, 5)); 
    prtCnt++; 
    SEXP OS = PROTECT(Rf_allocVector(VECSXP, 2)); 
    prtCnt++; 
    SET_VECTOR_ELT(OS, 0, a); 
    SET_VECTOR_ELT(OS, 1, b); 

    SEXP n = PROTECT(Rf_allocVector(STRSXP, 2)); 
    prtCnt++; 
    SET_STRING_ELT(n, 0, Rf_mkChar("a")); 
    SET_STRING_ELT(n, 1, Rf_mkChar("b")); 
    Rf_setAttrib(OS, R_NamesSymbol, n); 

    UNPROTECT(prtCnt); 
    return OS; 
} 

// [[Rcpp::export]] 
SEXP do_bla2() { 
    return Rcpp::List::create(
     Rcpp::Named("a") = Rcpp::NumericMatrix(5, 5), 
     Rcpp::Named("b") = Rcpp::NumericVector(5)); 
} 

// [[Rcpp::export]] 
SEXP do_bla3() { 
    Rcpp::NumericMatrix m(5, 5); 
    Rcpp::NumericVector v(5); 
    Rcpp::List res = Rcpp::List::create(m, v); 
    res.names() = Rcpp::CharacterVector::create("a", "b"); 
    return res; 
} 

직접 <Rinternals.h>를 사용하는 경우 당신은 mkCharsetAttrib 대신 Rf_mkCharRf_setAttrib을 사용해야 할 수도 있습니다 : 여기에 원래 기능의 수정 된 버전과 함께 두 가지 대안이 있습니다.


do_bla() 
# $a 
#    [,1]   [,2]   [,3]   [,4]   [,5] 
# [1,] 2.371515e-322 4.743030e-322 9.654277e-315 8.695555e-322 6.518868e-310 
# [2,] 2.794759e-316 2.371515e-322 6.763004e-317 2.371515e-322 6.952759e-310 
# [3,] 3.458460e-323 2.797257e-316 1.630417e-322 2.852530e-316 1.630417e-322 
# [4,] 6.441834e+170 1.976263e-323 4.092581e-316 1.976263e-323 4.125824e-316 
# [5,] 1.818440e-306 6.952931e-310 4.008825e-316 2.121996e-314 2.154669e-316 
# 
# $b 
# [1] 2.144130e-316 2.168146e-316 3.468674e-316 2.155101e-316 2.172224e-316 
# 
do_bla2() 
# $a 
#  [,1] [,2] [,3] [,4] [,5] 
# [1,] 0 0 0 0 0 
# [2,] 0 0 0 0 0 
# [3,] 0 0 0 0 0 
# [4,] 0 0 0 0 0 
# [5,] 0 0 0 0 0 
# 
# $b 
#[1] 0 0 0 0 0 

do_bla3() 
# $a 
#  [,1] [,2] [,3] [,4] [,5] 
# [1,] 0 0 0 0 0 
# [2,] 0 0 0 0 0 
# [3,] 0 0 0 0 0 
# [4,] 0 0 0 0 0 
# [5,] 0 0 0 0 0 
# 
# $b 
#[1] 0 0 0 0 0 
관련 문제