Skip to content

Commit 05eea3d

Browse files
authored
Merge pull request #1099 from waltersom/fix_dataframe_push
Implement push_back and push_front for DataFrame.
2 parents 85f6b27 + ff14167 commit 05eea3d

File tree

4 files changed

+203
-0
lines changed

4 files changed

+203
-0
lines changed

ChangeLog

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
2020-07-09 Walter Somerville <[email protected]>
2+
3+
* inst/include/Rcpp/DataFrame.h: Warn when data.frame has varying length
4+
* inst/tinyTest/cpp/DataFrame.cpp: Test added
5+
* inst/tinyTest/test_dataframe.R: Idem
6+
7+
2020-07-07 Walter Somerville <[email protected]>
8+
9+
* inst/include/Rcpp/DataFrame.h: Implement explict push_back and
10+
push_front for DataFrame, which takes care to set the class and
11+
row.names attributes.
12+
* inst/tinyTest/test_dataframe.R: Add in tests for push_back/push_front
13+
* inst/tinyTest/cpp/DataFrame.cpp: Idem
14+
115
2020-07-06 Dirk Eddelbuettel <[email protected]>
216

317
* DESCRIPTION (Version, Date): Roll minor version

inst/include/Rcpp/DataFrame.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,30 @@ namespace Rcpp{
8383
return LENGTH(rn);
8484
}
8585

86+
template <typename T>
87+
void push_back( const T& object){
88+
Parent::push_back(object);
89+
set_type_after_push();
90+
}
91+
92+
template <typename T>
93+
void push_back( const T& object, const std::string& name ){
94+
Parent::push_back(object, name);
95+
set_type_after_push();
96+
}
97+
98+
template <typename T>
99+
void push_front( const T& object){
100+
Parent::push_front(object);
101+
set_type_after_push();
102+
}
103+
104+
template <typename T>
105+
void push_front( const T& object, const std::string& name){
106+
Parent::push_front(object, name);
107+
set_type_after_push();
108+
}
109+
86110
// Offer multiple variants to accomodate both old interface here and signatures in other classes
87111
inline int nrows() const { return DataFrame_Impl::nrow(); }
88112
inline int rows() const { return DataFrame_Impl::nrow(); }
@@ -106,6 +130,30 @@ namespace Rcpp{
106130
}
107131
}
108132

133+
void set_type_after_push(){
134+
int max_rows = 0;
135+
bool invalid_column_size = false;
136+
SEXP data = Parent::get__();
137+
List::iterator it;
138+
// Get the maximum number of rows
139+
for (it = Parent::begin(); it != Parent::end(); ++it) {
140+
if (Rf_xlength(*it) > max_rows) {
141+
max_rows = Rf_xlength(*it);
142+
}
143+
}
144+
for (it = Parent::begin(); it != Parent::end(); ++it) {
145+
if (Rf_xlength(*it) == 0 || ( Rf_xlength(*it) > 1 && max_rows % Rf_xlength(*it) != 0 )) {
146+
// We have a column that is not an integer fraction of the largest
147+
invalid_column_size = true;
148+
}
149+
}
150+
if (invalid_column_size) {
151+
warning("Column sizes are not equal in DataFrame::push_back, object degrading to List\n");
152+
} else {
153+
set__(Parent::get__());
154+
}
155+
}
156+
109157
static DataFrame_Impl from_list( Parent obj ){
110158
bool use_default_strings_as_factors = true ;
111159
bool strings_as_factors = true ;

inst/tinytest/cpp/DataFrame.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,101 @@ IntegerVector DataFrame_nrow( DataFrame df){
9494
IntegerVector DataFrame_ncol( DataFrame df){
9595
return IntegerVector::create(df.ncol(), df.cols());
9696
}
97+
98+
// [[Rcpp::export]]
99+
DataFrame DataFrame_PushBackNamed(){
100+
NumericVector u(2);
101+
NumericVector v(2);
102+
DataFrame df = DataFrame::create(_["u"] = u);
103+
df.push_back(v, "v");
104+
return df;
105+
}
106+
107+
// [[Rcpp::export]]
108+
DataFrame DataFrame_PushBackUnnamed(){
109+
NumericVector u(2);
110+
NumericVector v(2);
111+
DataFrame df = DataFrame::create(_["u"] = u);
112+
df.push_back(v);
113+
return df;
114+
}
115+
116+
// [[Rcpp::export]]
117+
DataFrame DataFrame_PushFrontNamed(){
118+
NumericVector u(2);
119+
NumericVector v(2);
120+
DataFrame df = DataFrame::create(_["u"] = u);
121+
df.push_front(v, "v");
122+
return df;
123+
}
124+
125+
// [[Rcpp::export]]
126+
DataFrame DataFrame_PushFrontUnnamed(){
127+
NumericVector u(2);
128+
NumericVector v(2);
129+
DataFrame df = DataFrame::create(_["u"] = u);
130+
df.push_front(v);
131+
return df;
132+
}
133+
134+
// [[Rcpp::export]]
135+
DataFrame DataFrame_PushFrontDataFrame(){
136+
NumericVector u(2);
137+
NumericVector v(2);
138+
NumericVector w(2);
139+
NumericVector x(2);
140+
141+
DataFrame df1 = DataFrame::create(_["u"] = u, _["v"] = v);
142+
DataFrame df2 = DataFrame::create(_["w"] = w, _["x"] = x);
143+
df1.push_front(df2);
144+
return df1;
145+
}
146+
147+
// [[Rcpp::export]]
148+
DataFrame DataFrame_PushBackDataFrame(){
149+
NumericVector u(2);
150+
NumericVector v(2);
151+
NumericVector w(2);
152+
NumericVector x(2);
153+
154+
DataFrame df1 = DataFrame::create(_["u"] = u, _["v"] = v);
155+
DataFrame df2 = DataFrame::create(_["w"] = w, _["x"] = x);
156+
df1.push_back(df2);
157+
return df1;
158+
}
159+
160+
// [[Rcpp::export]]
161+
DataFrame DataFrame_PushWrongSize(){
162+
NumericVector u(2);
163+
NumericVector v(3);
164+
165+
DataFrame df1 = DataFrame::create(_["u"] = u);
166+
df1.push_back(v);
167+
return df1;
168+
}
169+
170+
// [[Rcpp::export]]
171+
DataFrame DataFrame_PushReplicateLength(){
172+
NumericVector u(2);
173+
NumericVector v(4);
174+
NumericVector x(1);
175+
176+
u[0] = 1;
177+
x[0] = 2;
178+
179+
DataFrame df1 = DataFrame::create(_["u"] = u);
180+
df1.push_back(v, "v");
181+
df1.push_back(x, "x");
182+
return df1;
183+
}
184+
185+
// [[Rcpp::export]]
186+
DataFrame DataFrame_PushZeroLength(){
187+
NumericVector u(2);
188+
NumericVector v(0);
189+
190+
191+
DataFrame df1 = DataFrame::create(_["u"] = u);
192+
df1.push_back(v);
193+
return df1;
194+
}

inst/tinytest/test_dataframe.R

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,46 @@ expect_equal( DataFrame_nrow( df ), rep(nrow(df), 2) )
7070
# test.DataFrame.ncol <- function(){
7171
df <- data.frame( x = 1:10, y = 1:10 )
7272
expect_equal( DataFrame_ncol( df ), rep(ncol(df), 2) )
73+
74+
# test.DataFrame.PushBackNamed <- function(){
75+
df <- data.frame( u = c(0, 0), v = c(0, 0) )
76+
expect_true( is.data.frame( DataFrame_PushBackNamed() ) )
77+
expect_equal( DataFrame_PushBackNamed(), df )
78+
79+
# test.DataFrame.PushBackUnamed <- function(){
80+
df <- data.frame( u = c(0, 0), c(0, 0) )
81+
expect_true( is.data.frame( DataFrame_PushBackUnnamed() ) )
82+
expect_equal( DataFrame_PushBackUnnamed(), df )
83+
84+
# test.DataFrame.PushFrontNamed <- function(){
85+
df <- data.frame( v = c(0, 0), u = c(0, 0) )
86+
expect_true( is.data.frame( DataFrame_PushFrontNamed() ) )
87+
expect_equal( DataFrame_PushFrontNamed(), df )
88+
89+
# test.DataFrame.PushFrontUnnamed <- function(){
90+
df <- data.frame( c(0, 0), u = c(0, 0) )
91+
expect_true( is.data.frame( DataFrame_PushFrontUnnamed() ) )
92+
expect_equal( DataFrame_PushFrontUnnamed(), df )
93+
94+
95+
# test.DataFrame.PushFrontDataFrame <- function(){
96+
df <- data.frame( w = c(0, 0), x = c(0, 0), u = c(0, 0), v = c(0, 0) )
97+
expect_true( is.data.frame( DataFrame_PushFrontDataFrame() ) )
98+
expect_equal( DataFrame_PushFrontDataFrame(), df )
99+
100+
# test.DataFrame.PushBackDataFrame <- function(){
101+
df <- data.frame( u = c(0, 0), v = c(0, 0), w = c(0, 0), x = c(0, 0) )
102+
expect_true( is.data.frame( DataFrame_PushBackDataFrame() ) )
103+
expect_equal( DataFrame_PushBackDataFrame(), df )
104+
105+
# test.DataFrame.PushWrongSize <- function(){
106+
df <- data.frame( u = c(0, 0), v = c(0, 0), w = c(0, 0), x = c(0, 0) )
107+
expect_warning( DataFrame_PushWrongSize() )
108+
109+
# test.DataFrame.PushReplicateLength <- function(){
110+
df <- data.frame( u = c(1, 0), v = c(0, 0, 0, 0), x = c(2) )
111+
expect_true( is.data.frame( DataFrame_PushReplicateLength() ) )
112+
expect_equal( DataFrame_PushReplicateLength(), df )
113+
114+
# test.DataFrame.PushZeroLength <- function(){
115+
expect_warning( DataFrame_PushZeroLength())

0 commit comments

Comments
 (0)