diff --git a/R/data.table.R b/R/data.table.R index 963d9cf72..ca0000cd5 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -687,11 +687,11 @@ chmatch2 <- function(x, table, nomatch=NA_integer_) { } if (!with) { # missing(by)==TRUE was already checked above before dealing with i - if (is.call(jsub) && jsub[[1]]==as.name("!")) { + if (is.call(jsub) && deparse(jsub[[1]], 500L) %in% c("!", "-")) { notj = TRUE - jsub = jsub[[2]] + jsub = jsub[[2L]] } else notj = FALSE - if (notj) j = eval(jsub, parent.frame(), parent.frame()) # else j will be evaluated for the first time on next line + j = eval(jsub, setattr(as.list(seq_along(x)), 'names', names(x)), parent.frame()) # else j will be evaluated for the first time on next line if (is.logical(j)) j <- which(j) if (!length(j)) return( null.data.table() ) if (is.factor(j)) j = as.character(j) # fix for FR: #4867 @@ -892,8 +892,9 @@ chmatch2 <- function(x, table, nomatch=NA_integer_) { # fix for #5190. colsub[[1L]] gave error when it's a symbol. if (is.call(colsub) && deparse(colsub[[1L]], 500L) %in% c("!", "-")) { colm = TRUE - .SDcols = eval(colsub[[2L]], parent.frame(), parent.frame()) + colsub = colsub[[2L]] } else colm = FALSE + .SDcols = eval(colsub, setattr(as.list(seq_along(x)), 'names', names(x)), parent.frame()) if (is.logical(.SDcols)) { ansvals = which_(rep(.SDcols, length.out=length(x)), !colm) ansvars = names(x)[ansvals] diff --git a/README.md b/README.md index 7aeb44065..145ea3380 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ * supports optional column prefixes as mentioned under [this SO post](http://stackoverflow.com/q/26225206/559784). Closes [#862](https://github.com/Rdatatable/data.table/issues/862). Thanks to @JohnAndrews. * works with undefined variables directly in formula. Closes [#1037](https://github.com/Rdatatable/data.table/issues/1037). Thanks to @DavidArenburg for the MRE. + 17. `.SDcols` and `with=FALSE` understand `colA:colB` form now. That is, `DT[, lapply(.SD, sum), by=V1, .SDcols=V4:V6]` and `DT[, V5:V7, with=FALSE]` works as intended. This is quite useful for interactive use. Closes [#748](https://github.com/Rdatatable/data.table/issues/748). + #### BUG FIXES 1. `if (TRUE) DT[,LHS:=RHS]` no longer prints, [#869](https://github.com/Rdatatable/data.table/issues/869). Tests added. To get this to work we've had to live with one downside: if a `:=` is used inside a function with no `DT[]` before the end of the function, then the next time `DT` is typed at the prompt, nothing will be printed. A repeated `DT` will print. To avoid this: include a `DT[]` after the last `:=` in your function. If that is not possible (e.g., it's not a function you can change) then `print(DT)` and `DT[]` at the prompt are guaranteed to print. As before, adding an extra `[]` on the end of `:=` query is a recommended idiom to update and then print; e.g. `> DT[,foo:=3L][]`. Thanks to Jureiss for reporting. diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 86a77a0fa..f6403ab0b 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -6231,6 +6231,23 @@ test(1503.1, uniqueN(dt), 4L) # default on key columns test(1503.2, uniqueN(dt, by=NULL), 6L) # on all columns test(1503.3, uniqueN(dt$col1), 4L) # on just that column +# .SDcols and with=FALSE understands colstart:colend syntax +dt = setDT(lapply(1:10, function(x) sample(3, 10, TRUE))) +# .SDcols +test(1504.1, dt[, lapply(.SD, sum), by=V1, .SDcols=V8:V10], + dt[, lapply(.SD, sum), by=V1, .SDcols=8:10]) +test(1504.2, dt[, lapply(.SD, sum), by=V1, .SDcols=V10:V8], + dt[, lapply(.SD, sum), by=V1, .SDcols=10:8]) +test(1504.3, dt[, lapply(.SD, sum), by=V1, .SDcols=-(V8:V10)], + dt[, lapply(.SD, sum), by=V1, .SDcols=-(8:10)]) +test(1504.4, dt[, lapply(.SD, sum), by=V1, .SDcols=!(V8:V10)], + dt[, lapply(.SD, sum), by=V1, .SDcols=!(8:10)]) +# with=FALSE +test(1504.5, dt[, V8:V10, with=FALSE], dt[, 8:10, with=FALSE]) +test(1504.6, dt[, V10:V8, with=FALSE], dt[, 10:8, with=FALSE]) +test(1504.7, dt[, -(V8:V10), with=FALSE], dt[, -(8:10), with=FALSE]) +test(1504.8, dt[, !(V8:V10), with=FALSE], dt[, !(8:10), with=FALSE]) + ##########################