r — лучшая идиома для заполнения массива C ++ из NumericVector

я использую Rcpp обернуть алгоритм, написанный (не мной) на C-подобном C ++ (без STL, без наддува, без ничего, насколько я могу судить). Вы можете увидеть реализованный алгоритм Вот (Я оборачиваюсь kmeans_w_03). Следовательно, я прохожу в numeric вектор из R, который затем должен быть преобразован в double массив.

В настоящее время я зацикливаю элемент за элементом и заполняю один из ‘tother, вот так:

SEXP testfn(SEXP weightvec, SEXP cluster_num_k){
Rcpp::NumericVector weightR(weightvec) ;
int point_num = weightR.size();
double weight[point_num] ;
for(int i = 0; i < point_num; ++i) {
weight[i] = weightR[i];
}
}

Но с одноэлементными числовыми векторами, я могу воспользоваться красивым Rcpp as Функциональность кастинга:

int cluster_num = Rcpp::as<int>(cluster_num_k);

Однако попытка чего-то подобного для длинных> 1 числовых векторов приводит к падению или ошибке, в зависимости от точного варианта синтаксиса:

double weight[point_num] = Rcpp::as<double>(weightvec);

Я не обязательно возражаю против этой петли, но я неофит и подозреваю, что есть лучший способ. Я прочитал Rcpp-введение, вики-уроки Хадли и RcppExamples и еще не нашел ничего, что решило бы этот вопрос, но это не значит, что я не пропустил его. Мое чтение документов Doxygen Rcpp заключается в том, что as может привести к вектору STL, но не к массиву (но мне очень трудно читать эти документы, поэтому я подозреваю, что я ошибаюсь). Если так, я думаю, я мог бы привести к вектору, а затем к массиву ….

Поэтому мой вопрос: есть ли лучший (меньше строк кода, более выразительный код и, возможно, даже способ избежать выделения памяти) для преобразования NumericVector к double[]?

8

Решение

Ари, в предыдущем ответе Джон делает хорошую мысль. Чтобы немного расширить, здесь есть несколько вопросов

  • вы имеете дело с библиотекой с устаревшим стандартом кодирования, которая хочет double[] или же *double
  • Вы хотите использовать лучшие стандарты кодирования и воспользоваться Rcpp.

Ну, не бойся, у нас есть простое решение. Instantantiate Rcpp::NumericVector X(weightvec); как обычно, а затем передать его в свою функцию foo() (или что угодно) как

foo(X.begin())

что дает вам необходимое double*и при необходимости X.size() обеспечивает длину. Поскольку вы пришли из R, вам не нужно беспокоиться о масштабах и сроке службы, когда вы вернетесь к R впоследствии.

В случае, если вам нужно быть более явным, я также использовал более уродливый &(X[0]),

Так же Rcpp::as<>() Заклинатель также работает на std::vector<double>так что вы можете сделать

std::vector<double> x = Rcpp::as<std::vector<double> >(weightvec);

но кроме преобразования в типы C ++ здесь ничего не получается.

Наконец, в случае, если Джош или другие преданные С находятся поблизости, все это использует тот факт, что SEXP у вас из R гарантированно есть непрерывный указатель C, так что вы также можете пройти через очень старую школу REAL(weightvec),

8

Другие решения

Написание программы на C ++, в которой не используется Стандартная библиотека (то, что вы называете «STL»), — это не то, что я бы назвал «обычным C ++». Стандартная библиотека часть язык в соответствии со стандартом. Таким образом, использование средств, определенных в Стандарте, не является нетрадиционным C ++. Напротив, я бы предположил, что намеренное игнорирование этих средств само по себе нетрадиционно. Он использует C ++ в качестве «лучшего C» или «C с классами». и это упускает суть.

Принимая это во внимание, при взгляде на то, что ваша петля намеревается выполнить, я хочу использовать transform скопировать источник в пункт назначения и vector в качестве пункта назначения.

У вас также есть посредник на работе здесь — вы первый (кажется,) копия weightVec недавно построенному NumericVector, а затем скопировать элементы из этого — но NumericVector выбрасывается Это кажется расточительным для меня.

Вот основной шаблон, который я хотел бы иметь в виду при написании этого кода:

vector<double> weight;
transform( weightVec.begin(), weightVec.end(), back_inserter(weight), converter() );
return weight;

Здесь отсутствуют некоторые синтаксические биты, которые я не могу заполнить, не зная больше о составляющих в игре. Но, учитывая то, что вы делаете, философия кажется здравой.

Например, SEXP объект может не иметь begin() или же end() методы. Однако вы уже строите NumericVector от SEXP объект, так что SEXP вероятно, имеет аналоговые средства для begin() а также end() что вы можете принять или, возможно, даже использовать напрямую.

converter() Конструкция, которую я использую выше, является заполнителем для функции, функтора или лямбды (в C ++ 11), которая преобразует один SEXP элемент в double, Опять же, я не знаю деталей, которые мне нужны, чтобы реализовать это, но это должно быть возможно, так как вы уже делаете это по-другому.

4

Если ваш вопрос, как скопировать данные из Rcpp::NumericVector в массив C ++, transform() хороший ответ Но если вы хотите получить внутренний массив из Rcpp::NumericVector, который не включает в себя копирование, вы можете сделать точно так же, как извлечение массива из std::vector:

double* arr = &vec[0];

где vec является Rcpp::NumericVector,

0
По вопросам рекламы [email protected]