我刚刚在Rcpp
.
我不知道如何使用...
参数(以及如何对其进行迭代),Rcpp
所以我将此函数封装在一个简单的R
函数中。
解决方案
library(Rcpp)
cppFunction(
code = '
NumericVector add_vectors_cpp(NumericVector v1, NumericVector v2) {
// merging names, sorting them and removing duplicates
std::vector<std::string> nms1 = v1.names();
std::vector<std::string> nms2 = v2.names();
std::vector<std::string> nms;
nms.resize(nms1.size() + nms2.size());
std::merge(nms1.begin(), nms1.end(), nms2.begin(), nms2.end(), nms.begin());
std::sort(nms.begin(), nms.end());
nms.erase(std::unique(nms.begin(), nms.end()), nms.end());
// summing vector elements by their names and storing them in an associative data structure
int num_names = nms.size();
std::tr1::unordered_map<std::string, double> map(num_names);
for (std::vector<int>::size_type i1 = 0; i1 != nms1.size(); i1++) {
map[nms1[i1]] += v1[i1];
}
for (std::vector<int>::size_type i2 = 0; i2 != nms2.size(); i2++) {
map[nms2[i2]] += v2[i2];
}
// extracting map values (to use as result vector) and keys (to use as result vector names)
NumericVector vals(map.size());
for (unsigned r = 0; r < num_names; ++r) {
vals[r] = map[nms[r]];
}
vals.names() = nms;
return vals;
}',
includes = '
#include <vector>
#include <tr1/unordered_map>
#include <algorithm>'
)
然后封装在一个R
函数中:
add_vectors_2 <- function(...) {
Reduce(function(x, y) add_vectors_cpp(x, y), list(...))
}
请注意,此解决方案使用STL
库。我不知道这是否是一个写得很好的 C++解决方案,或者是否可以(可能)编写一个更有效的解决方案,但可以肯定它是一个好的(和工作的)起点。
使用示例
v1 <- c(b = 1, d = 2, c = 3, a = 4, e = 6, f = 5)
v2 <- c(d = 2, c = 3, a = 4, e = 6, f = 5)
add_vectors(v1, v2, v1, v2)
# a b c d e f
# 16 2 12 8 24 20
add_vectors_2(v1, v2, v1, v2)
# a b c d e f
# 16 2 12 8 24 20
注意:此函数也适用于名称不是唯一的向量。
v1 <- c(b = 1, d = 2, c = 3, a = 4, e = 6, f = 5)
v2 <- c(d = 2, c = 3, a = 4, e = 6, f = 5, f = 10, a = 12)
add_vectors(v1, v2)
# a b c d e f
# 16 1 6 4 12 15
add_vectors_2(v1, v2)
# a b c d e f
# 20 1 6 4 12 20
如上一个示例所示,即使输入向量具有非唯一名称,该解决方案也有效,将具有相同名称的相同向量的元素相加。
基准
R
在最简单的情况下(两个向量),我的解决方案比解决方案快大约 3 倍。这是一个很好的改进,但可能还有更好的C++
解决方案进行进一步小的改进的空间。
Unit: microseconds
expr min lq median uq max neval
add_vectors(v1, v2) 65.460 68.569 70.913 73.5205 614.274 100
add_vectors_2(v1, v2) 20.743 23.389 25.142 26.9920 337.544 100
当将此函数应用于更多向量时,性能会有所下降(仅快 2 倍)。
Unit: microseconds
expr min lq median uq max neval
add_vectors(v1, v2, v1, v2, v1, v1) 105.994 195.7565 205.174 212.5745 993.756 100
add_vectors_2(v1, v2, v1, v2, v1, v1) 66.168 125.2110 135.060 139.7725 666.975 100
所以现在的最后一个目标是删除R
直接使用....
List
Rcpp
我认为这是可能的,因为Rcpp
糖具有与其相似的功能(例如功能的移植sapply
),但希望得到一些反馈。