困难在于数据框是一组向量,可能具有不同类型;我们需要一种独立于这些类型(整数、字符……)对它们进行排序的方法。在 dplyr 中,我们开发了所谓的矢量访问者。对于这个特定的问题,我们需要的是一组OrderVisitor
,其显示以下界面:
class OrderVisitor {
public:
virtual ~OrderVisitor(){}
/** are the elements at indices i and j equal */
virtual bool equal(int i, int j) const = 0 ;
/** is the i element less than the j element */
virtual bool before( int i, int j) const = 0 ;
virtual SEXP get() = 0 ;
} ;
dplyr 然后有以下实现OrderVisitor
对于我们在此支持的所有类型file https://github.com/hadley/dplyr/blob/master/inst/include/dplyr/OrderVisitorImpl.h我们有一个调度程序功能order_visitor
这使得OrderVisitor*
来自向量。
有了这个,我们可以将一组向量访问者存储到一个std::vector<OrderVisitor*>
; The 订单访客 https://github.com/hadley/dplyr/blob/master/inst/include/dplyr/Order.h#L8有一个构造函数采用DataFrame
and a CharacterVector
我们想要用于排序的向量名称。
OrderVisitors o(data, names ) ;
然后我们可以使用OrderVisitors.apply method https://github.com/hadley/dplyr/blob/master/inst/include/dplyr/Order.h#L76它本质上是按字典顺序排序的:
IntegerVector index = o.apply() ;
The apply
方法是通过简单地初始化一个来实现的IntegerVector
with 0..n
进而std::sort
据参观者说。
inline Rcpp::IntegerVector OrderVisitors::apply() const {
IntegerVector x = seq(0, nrows -1 ) ;
std::sort( x.begin(), x.end(), OrderVisitors_Compare(*this) ) ;
return x ;
}
这里相关的是如何OrderVisitors_Compare
类工具operator()(int,int)
:
inline bool operator()(int i, int j) const {
if( i == j ) return false ;
for( int k=0; k<n; k++)
if( ! obj.visitors[k]->equal(i,j) )
return obj.visitors[k]->before(i, j ) ;
return i < j ;
}
所以此时index
给我们排序数据的整数索引,我们只需要创建一个新的DataFrame
from data
通过子集化data
与这些指数。为此,我们有另一种访客,封装在DataFrameVisitors
班级。我们首先创建一个DataFrameVisitors https://github.com/hadley/dplyr/blob/master/inst/include/dplyr/DataFrameVisitors.h :
DataFrameVisitors visitors( data ) ;
这封装了一个std::vector<VectorVisitor*>
。这些中的每一个VectorVisitor*
知道如何使用整数向量索引对自身进行子集化。这是使用自DataFrameVisitors.subset
:
template <typename Container>
DataFrame subset( const Container& index, const CharacterVector& classes ) const {
List out(nvisitors);
for( int k=0; k<nvisitors; k++){
out[k] = get(k)->subset(index) ;
}
structure( out, Rf_length(out[0]) , classes) ;
return (SEXP)out ;
}
为了总结这一点,这里是一个使用 dplyr 开发的工具的简单函数:
#include <dplyr.h>
// [[Rcpp::depends(dplyr)]]
using namespace Rcpp ;
using namespace dplyr ;
// [[Rcpp::export]]
DataFrame myFunc(DataFrame data, CharacterVector names) {
OrderVisitors o(data, names ) ;
IntegerVector index = o.apply() ;
DataFrameVisitors visitors( data ) ;
DataFrame res = visitors.subset(index, "data.frame" ) ;
return res ;
}