第 8 章 Vector类
8.1 创建向量对象
你可以使用下面的几种方法来创建向量对象。
// 等价于 v <- rep(0, 3)
NumericVector v (3);
// 等价于 v <- rep(1, 3)
NumericVector v (3,1);
// 等价于 v <- c(1,2,3)
// C++11 初始化列表
NumericVector v = {1,2,3};
// 等价于 v <- c(1,2,3)
NumericVector v = NumericVector::create(1,2,3);
// 命名向量 等价于 v <- c(x=1, y=2, z=3)
NumericVector v =
NumericVector::create(Named("x",1), Named("y")=2 , _["z"]=3);
8.2 获取向量元素
你可以使用[]
或 ()
运算符来获取一个向量的个别元素。两种操作符都接受 数值向量/整型向量(NumericVector/IntegerVector) 的数值索引,字符向量的元素名索引和逻辑向量。[]
运算符会忽略边界溢出,而()
运算符会抛出index_out_of_bounds
错误。
需要注意的是 C++中的向量索引开始于0
// [[Rcpp::export]]
void rcpp_vector_access(){
// 创建向量
NumericVector v {10,20,30,40,50};
// 设置元素名称
v.names() = CharacterVector({"A","B","C","D","E"});
// 准备向量索引
NumericVector numeric = {1,3};
IntegerVector integer = {1,3};
CharacterVector character = {"B","D"};
LogicalVector logical = {false, true, false, true, false};
// 根据向量索引获取向量元素值
double x1 = v[0];
double x2 = v["A"];
NumericVector res1 = v[numeric];
NumericVector res2 = v[integer];
NumericVector res3 = v[character];
NumericVector res4 = v[logical];
// 向量元素赋值
v[0] = 100;
v["A"] = 100;
NumericVector v2 {100,200};
v[numeric] = v2;
v[integer] = v2;
v[character] = v2;
v[logical] = v2;
}
8.3 成员函数
成员函数(也被称作方法)是某个对象中的函数。你可以以v.f()
的形式来调用对象v
中的成员函数f()
。
Rcpp中,向量对象的成员函数列举如下。
8.3.1 length(), size()
返回该向量对象中元素的个数。
//test.cpp 文件
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
int test(NumericVector v) {
Rcout << v.length() << '\n';
Rcout << v.size() << '\n';
return 0;
}
在R中,运行结果为:
8.3.2 names()
以字符向量的形式,返回该向量的元素名称。
//test.cpp 文件
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
CharacterVector test(NumericVector v) {
return v.names();
}
在R中,运行结果为:
8.3.3 offset( name ), findName( name )
按照指定字符串name
的方式,返回对应元素的数值索引。
//test.cpp 文件
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
int test(NumericVector v, std::string name) {
return v.offset(name);
}
在R中,运行结果为:
8.3.4 offset( i )
函数在检查数值索引i没有超过边界后,返回该索引。
举例说明,在test.cpp
文件中键入以下代码,
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
int test(NumericVector v, int i) {
return v.offset(i);
}
在R中,运行结果为:
8.3.5 fill( x )
将该向量的所有元素用标量x
填充。
举例说明,在test.cpp
文件中键入以下代码,
8.3.6 sort()
将该向量对象中的元素升序排列。
举例说明,在test.cpp
文件中键入以下代码,
8.3.7 assign( first_it, last_it )
assign values specified by the iterator first_it
and last_it
to this vector object.
将迭代器first_it
至lates_it
所指向的元素赋给向量对象。
举例说明,在test.cpp
文件中键入以下代码,
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector test(NumericVector v) {
NumericVector v1;
v1.assign(v.begin(),v.end());
return v1;
}
begin
和end
也是成员函数,下面8.3.12也有对应的例子
8.3.8 push_back( x )
在向量对象的最后加入新的标量值 x
。
在test.cpp
文件中键入以下代码,
8.3.9 push_back( x, name )
在向量后加入标量元素x
时,指定其元素名称。
在test.cpp
文件中键入以下代码,
8.3.10 push_front( x )
在向量前面加入一个标量x
。
在test.cpp
文件中键入以下代码,
8.3.11 push_front( x, name )
在向量前加入标量元素x
时,指定其元素名称。
在test.cpp
文件中键入以下代码,
8.3.12 begin()
返回一个指向向量第一个元素的迭代器。
8.3.13 end()
返回一个指向向量最后一个元素的迭代器。 (one past the last element of this vector).
以求和函数说明begin()
和end()
的作用。
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
double test(NumericVector v) {
double mysum = 0;
NumericVector::iterator it;
for(it = v.begin();it!=v.end();it++){
mysum += *it;
}
return mysum;
}
在循环体内,我们用*it获取向量v中的元素,在指明循环范围的时候,也并不是我们熟悉的 int i = 0; i < n; i++
该例子来源于Advanced R中案例,请点击传送门。
8.3.14 cbegin()
返回一个指向向量第一个元素的具有const属性的迭代器。
无法用于元素的修改
8.3.15 cend()
返回一个指向向量最后一个元素的具有const属性的迭代器。 (one past the last element of this vector).
以求和函数说明cbegin()
和cend()
的作用。下面的例子只在声明迭代器it的时候,将iterator改为const_iterator,因为cbegin()
和cend()
得到是const_iterator.
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
double test(NumericVector v) {
double mysum = 0;
NumericVector::const_iterator it;
for(it = v.begin();it!=v.end();it++){
mysum += *it;
}
return mysum;
}
当然,对于c++不熟悉的用户,完全可以忽视
const_iterator
。不声明it,而是采用auto,如下。
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::export]]
double test(NumericVector v) {
double mysum = 0;
for(auto it = v.cbegin();it!=v.cend();it++){
mysum += *it;
}
return mysum;
}
上面的这段代码,在循环体中,使用auto,来自动判别it的类型。对于不熟悉C++的用户而言(也包括我),是十分便捷的。但需要注意的是,一定要加上// [[Rcpp::plugins(cpp11)]]
,表明你希望使用c++11的新特性,否则程序会报错。
8.3.16 insert( i, x )
在数值索引i
指定的位置插入标量x
。返回一个指向插入元素的迭代器。
test.cpp文件如下:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector test(NumericVector v) {
v.insert(1,6);
return v;
}
R运行结果如下:
8.3.17 insert( it, x )
在迭代器it
指定的位置插入标量x
。返回迭代器指向的元素。
test.cpp文件如下:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector test(NumericVector v) {
v.insert(v.begin()+1,6);
return v;
}
R运行结果如下:
8.3.18 erase(i)
擦除数值索引i
指定的标量元素x
。返回指向擦除元素之后一个元素的迭代器。
test.cpp文件如下:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
double test(NumericVector v) {
NumericVector::iterator it = v.erase(0);
return *it;
}
R运行结果如下:
8.3.19 erase(it)
擦除迭代器it
指向的元素。返回指向擦除元素之后一个元素的迭代器。
test.cpp文件如下:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
double test(NumericVector v) {
NumericVector::iterator it = v.erase(v.begin());
return *it;
}
R运行结果如下:
8.3.20 erase( first_i, last_i )
擦除数值索引first_i
至last_i - 1
之间的所有元素。返回指向擦除元素之后一个元素的迭代器。
test.cpp文件如下:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
double test(NumericVector v) {
NumericVector::iterator it = v.erase(0,3);
return *it;
}
R运行结果如下:
由于擦除的是索引0和3-1,即,第1个元素至第3个元素被擦除,返回的是对应原本第四个元素的迭代器,*it为4,也印证了结果。
8.3.21 erase( first_it, last_it )
擦除迭代器first_it
至last_it - 1
之间的所有元素。返回指向擦除元素之后一个元素的迭代器。
test.cpp文件如下:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
double test(NumericVector v) {
NumericVector::iterator it = v.erase(v.begin(),v.end());
return *it;
}
R运行结果如下:
8.3.22 containsElementNamed(name)
如果向量包含有某一个元素,其名称与字符串name相同,那么返回true
。
test.cpp文件如下:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
bool test(NumericVector v) {
if(v.containsElementNamed("b")){
Rcout <<"name is included" << '\n';
}else{
Rcout <<"name is not included" << '\n';
}
return v.containsElementNamed("b");
}
R运行结果如下:
8.4 静态成员函数
静态成员函数是对象所在类的函数。k可以按照 NumericVector::create()
的方式来调用该静态成员函数。
8.4.1 get_na()
返回Vector
类中的NA
值。
test.cpp文件如下:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector test(NumericVector v) {
v.fill(NumericVector::get_na());
return v;
}
R运行结果如下:
该例子有参考stackoverflow上的答案,详情点击传送门。
8.4.2 is_na(x)
如果x
为NA
,则返回true
。
test.cpp文件如下:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
bool test(NumericVector v,int id) {
return NumericVector::is_na(v(id));
}
R运行结果如下:
8.4.3 create( x1, x2, …)
创建一个Vector
对象,其包含的元素由标量x1
,x2
指定。参数最大个数为20。
可以命名元素或不命名,例子如下:
8.4.4 import( first_it , last_it )
创建一个Vector
对象,其元素由迭代器first_it
至 last_it - 1
指定。
8.4.5 import_transform( first_it, last_it, func)
在import( first_it , last_it )
的基础上,对于每一个迭代器范围内的元素,进行func
函数的操作。类似于apply()
函数族。