困难在于数据框是一组向量,可能是不同类型的; 我们需要一种方法来独立于这些类型(整数、字符等)对它们进行排序。在dplyr中,我们开发了所谓的向量访问器。对于这个特定的问题,我们需要一组OrderVisitor
,它们展示以下接口:
class OrderVisitor {
public:
virtual ~OrderVisitor(){}
virtual bool equal(int i, int j) const = 0 ;
virtual bool before( int i, int j) const = 0 ;
virtual SEXP get() = 0 ;
} ;
dplyr提供了OrderVisitor
的实现,适用于我们在此文件中支持的所有类型,并且我们有一个调度函数order_visitor
,它可以从向量创建一个OrderVisitor*
。
有了这个,我们可以将一组向量访问者存储到std::vector<OrderVisitor*>
中;OrderVisitors有一个构造函数,它接受一个DataFrame
和一个CharacterVector
,表示我们想要用于排序的向量名称。
OrderVisitors o(data, names ) ;
然后我们可以使用OrderVisitors.apply
方法,该方法基本上执行词典排序:
IntegerVector index = o.apply() ;
apply
方法的实现是通过用0..n
初始化一个IntegerVector
,然后根据访问者使用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
给出了已排序数据的整数索引,我们只需通过使用这些索引来对 data
进行子集化,从而创建一个新的 DataFrame
。为此,我们有另一种访问者,它包含在 DataFrameVisitors
类中。我们首先创建一个DataFrameVisitors
:
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>
using namespace Rcpp ;
using namespace dplyr ;
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 ;
}
myFunc
吗? - G. Grothendieckdplyr
的新版本发布了吗? - udayinstall_github( "hadley/dplyr" )
- Romain Francois