diff --git a/R/data.table.R b/R/data.table.R index 1f5af08be..f14e993d5 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -394,6 +394,18 @@ chmatch2 <- function(x, table, nomatch=NA_integer_) { isub = substitute(i) # Fixes 4994: a case where quoted expression with a "!", ex: expr = quote(!dt1); dt[eval(expr)] requires # the "eval" to be checked before `as.name("!")`. Therefore interchanged. + restore.N = remove.N = FALSE + if (exists(".N", envir=parent.frame(), inherits=FALSE)) { + old.N = get(".N", envir=parent.frame(), inherits=FALSE) + if (!bindingIsLocked(".N", parent.frame())) { + assign(".N", nrow(x), envir=parent.frame(), inherits=FALSE) + restore.N = TRUE + } # binding locked when .SD[.N] but that's ok as that's the .N we want anyway + # TO DO: change isub at C level s/.N/nrow(x); changing a symbol to a constant should be ok + } else { + assign(".N", nrow(x), envir=parent.frame(), inherits=FALSE) + remove.N = TRUE + } if (is.call(isub) && isub[[1L]]=="eval") { # TO DO: or ..() isub = eval(.massagei(isub[[2L]]), parent.frame(), parent.frame()) if (is.expression(isub)) isub=isub[[1L]] @@ -416,7 +428,9 @@ chmatch2 <- function(x, table, nomatch=NA_integer_) { i = eval(isub, order_env, parent.frame()) # for optimisation of 'order' to 'forder' # that forder returns integer(0) is taken care of internally within forder } else if (!is.name(isub)) i = eval(.massagei(isub), x, parent.frame()) - else i = eval(isub, parent.frame(), parent.frame()) + else i = eval(isub, parent.frame(), parent.frame()) + if (restore.N) assign(".N", old.N, envir=parent.frame()) + if (remove.N) rm(list=".N", envir=parent.frame()) if (is.matrix(i)) stop("i is invalid type (matrix). Perhaps in future a 2 column matrix could return a list of elements of DT (in the spirit of A[B] in FAQ 2.14). Please let datatable-help know if you'd like this, or add your comments to FR #1611.") if (is.logical(i)) { if (notjoin) { diff --git a/README.md b/README.md index 592e09ec8..2bfa1d824 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,8 @@ We moved from R-Forge to GitHub on 9 June 2014, including history. 25. `setorder()` and `setorderv()` gain `na.last = TRUE/FALSE`. Closes [#706](https://github.com/Rdatatable/data.table/issues/706). + 26. `.N` is now available in `i`, [FR#724](https://github.com/Rdatatable/data.table/issues/724). Thanks to newbie indirectly [here](http://stackoverflow.com/a/24649115/403310) and Farrel directly [here](http://stackoverflow.com/questions/24685421/how-do-you-extract-a-few-random-rows-from-a-data-table-on-the-fly). + #### BUG FIXES 1. `fread()`: diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 7292021eb..4f00b551f 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -4872,6 +4872,13 @@ DT <- data.table(id=rep(1:2, c(3,2)), k=c(letters[1:3], letters[1:2]), v=1:5) test(1347.1, dcast.data.table(DT, id ~ k, fun.aggregate=last, value.var="v"), error="Aggregating function provided to argument 'fun.aggregate' should always return a length 1 vector") test(1347.2, dcast.data.table(DT, id ~ k, fun.aggregate=last, value.var="v", fill=NA_integer_), data.table(id=1:2, a=c(1L, 4L), b=c(2L,5L), c=c(3L,NA_integer_), key="id")) +# .N now available in i +DT = data.table(a=1:3,b=1:6) +test(1348, DT[.N], DT[6]) +test(1349, DT[.N-1:3], DT[5:3]) +test(1350, DT[.N+1], DT[NA]) + + ##########################