将 R split() 函数转换为 C++
Converting R split() function to C++
考虑 R 中的可重现示例:
test <- c(1:12)
> test
[1] 1 2 3 4 5 6 7 8 9 10 11 12
预期结果:
test.list <- split(test, gl(2, 3))
> test.list
$`1`
[1] 1 2 3 7 8 9
$`2`
[1] 4 5 6 10 11 12
我正在尝试用 C++ 编写等效代码来生成 return 由 test.list 产生的两个向量。请注意,我在C++中处于尴尬的新手阶段
试试这个,它创建一个包含交替块中的源元素的向量向量:
#include <iostream>
#include <vector>
template<typename T>
std::vector<std::vector<T>> split(std::vector<T> nums, int n, int size)
{
std::vector<std::vector<T>> result(n);
int i = 0;
auto beg = nums.cbegin();
auto end = nums.cend();
while (beg != nums.cend()) {
//get end iterator safely
auto next = std::distance(beg, end) >= size ? beg + size : end;
//insert into result
result[i].insert(result[i].end(), beg, next);
//advance iterator
beg = next;
i = (i + 1) % n;
}
return result;
}
int main()
{
std::vector<int> vnums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
auto vectors = split(vnums, 2, 3);
for (const auto& v : vectors)
{
for (auto num : v) {
std::cout << num << " ";
}
std::cout << std::endl;
}
}
我们可以使用@jignatius 的漂亮答案并将其设为 R 可调用函数。为简单起见,我将其保持在 NumericVector
;我们这里有大量答案,显示根据 运行 时间有效载荷在 NumericVector
和 IntegerVector
之间切换。
代码
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::List mysplit(Rcpp::NumericVector nums, int n, int size) {
std::vector<std::vector<double>> result(n);
int i = 0;
auto beg = nums.cbegin();
auto end = nums.cend();
while (beg != nums.cend()) {
//get end iterator safely
auto next = std::distance(beg, end) >= size ? beg + size : end;
//insert into result
result[i].insert(result[i].end(), beg, next);
//advance iterator
beg = next;
i = (i + 1) % n;
}
Rcpp::List ll;
for (const auto&v : result)
ll.push_back(v);
return ll;
}
/*** R
testvec <- 1:12
mysplit(testvec, 2, 3)
*/
输出
> Rcpp::sourceCpp("~/git/Whosebug/68858728/answer.cpp")
> testvec <- 1:12
> mysplit(testvec, 2, 3)
[[1]]
[1] 1 2 3 7 8 9
[[2]]
[1] 4 5 6 10 11 12
>
原问题中有一个小错误,我们不需要调用 gl()
;只需要两个标量。
考虑 R 中的可重现示例:
test <- c(1:12)
> test
[1] 1 2 3 4 5 6 7 8 9 10 11 12
预期结果:
test.list <- split(test, gl(2, 3))
> test.list
$`1`
[1] 1 2 3 7 8 9
$`2`
[1] 4 5 6 10 11 12
我正在尝试用 C++ 编写等效代码来生成 return 由 test.list 产生的两个向量。请注意,我在C++中处于尴尬的新手阶段
试试这个,它创建一个包含交替块中的源元素的向量向量:
#include <iostream>
#include <vector>
template<typename T>
std::vector<std::vector<T>> split(std::vector<T> nums, int n, int size)
{
std::vector<std::vector<T>> result(n);
int i = 0;
auto beg = nums.cbegin();
auto end = nums.cend();
while (beg != nums.cend()) {
//get end iterator safely
auto next = std::distance(beg, end) >= size ? beg + size : end;
//insert into result
result[i].insert(result[i].end(), beg, next);
//advance iterator
beg = next;
i = (i + 1) % n;
}
return result;
}
int main()
{
std::vector<int> vnums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
auto vectors = split(vnums, 2, 3);
for (const auto& v : vectors)
{
for (auto num : v) {
std::cout << num << " ";
}
std::cout << std::endl;
}
}
我们可以使用@jignatius 的漂亮答案并将其设为 R 可调用函数。为简单起见,我将其保持在 NumericVector
;我们这里有大量答案,显示根据 运行 时间有效载荷在 NumericVector
和 IntegerVector
之间切换。
代码
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::List mysplit(Rcpp::NumericVector nums, int n, int size) {
std::vector<std::vector<double>> result(n);
int i = 0;
auto beg = nums.cbegin();
auto end = nums.cend();
while (beg != nums.cend()) {
//get end iterator safely
auto next = std::distance(beg, end) >= size ? beg + size : end;
//insert into result
result[i].insert(result[i].end(), beg, next);
//advance iterator
beg = next;
i = (i + 1) % n;
}
Rcpp::List ll;
for (const auto&v : result)
ll.push_back(v);
return ll;
}
/*** R
testvec <- 1:12
mysplit(testvec, 2, 3)
*/
输出
> Rcpp::sourceCpp("~/git/Whosebug/68858728/answer.cpp")
> testvec <- 1:12
> mysplit(testvec, 2, 3)
[[1]]
[1] 1 2 3 7 8 9
[[2]]
[1] 4 5 6 10 11 12
>
原问题中有一个小错误,我们不需要调用 gl()
;只需要两个标量。