diff --git a/NEWS.md b/NEWS.md index 48f7c529e8..c6a878a39c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -269,7 +269,7 @@ 36. `unique.data.table()` gains `cols` to specify a subset of columns to include in the resulting `data.table`, [#5243](https://github.com/Rdatatable/data.table/issues/5243). This saves the memory overhead of subsetting unneeded columns, and provides a cleaner API for a common operation previously needing more convoluted code. Thanks to @MichaelChirico for the suggestion & implementation. -37. `:=` is now optimized by group, [#1414](https://github.com/Rdatatable/data.table/issues/1414). Thanks to Arun Srinivasan for suggesting, and Benjamin Schwendinger for the PR. Thanks to @clerousset, @dcaseykc, @OfekShilon, and @SeanShao98 for testing dev and filing detailed bug reports which were fixed before release and their tests added to the test suite. +37. `:=` is now optimized by group, [#1414](https://github.com/Rdatatable/data.table/issues/1414). Thanks to Arun Srinivasan for suggesting, and Benjamin Schwendinger for the PR. Thanks to @clerousset, @dcaseykc, @OfekShilon, @SeanShao98, and @ben519 for testing dev and filing detailed bug reports which were fixed before release and their tests added to the test suite. 38. `.I` is now available in `by` for rowwise operations, [#1732](https://github.com/Rdatatable/data.table/issues/1732). Thanks to Rafael H. M. Pereira for requesting, and Benjamin Schwendinger for the PR. diff --git a/R/data.table.R b/R/data.table.R index 801482147e..fb3fe7afa0 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -1912,6 +1912,9 @@ replace_dot_alias = function(e) { if (length(o__)) jrows = o__[jrows] if (length(irows)) jrows = irows[jrows] if (length(jvals)==1L) jvals = jvals[[1L]] # unwrap single column jvals for assign + if (.is_nrows(jsub)) { # 5403 unwrap multicolumn jvals for gfunctions that can return lists + jvals = if (length(jvals) != length(lhs)) split(unlist(jvals), rep(seq_along(jvals[[1L]]), length(jvals))) else lapply(jvals, unlist) + } .Call(Cassign, x, jrows, lhs, newnames, jvals) } if (any(names_x[cols] %chin% key(x))) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 8eeb8f7ee7..0a8f347496 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -1090,6 +1090,7 @@ test(351.2, DT[, c("a","b"):=13:15, verbose=TRUE], ans, notOutput="revised") test(352.1, DT[,letters[1:4]:=list(1L,NULL)], error="Supplied 4 columns to be assigned 2 items. Please see NEWS for v1.12.2") test(352.2, DT[,letters[1:4]:=list(1L,NULL,2L,NULL)], data.table(a=c(1L,1L,1L),c=c(2L,2L,2L))) +test(352.3, DT[,letters[1:2]:=list(1L,NULL,2L,NULL)], error="Supplied 2 columns to be assigned 4 items. Please see NEWS for v1.12.2") # Test assigning new levels into factor columns DT = data.table(f=factor(c("a","b")),x=1:4) @@ -18059,6 +18060,14 @@ for (opt in c(0,Inf)) { testnum = 2233.44 } options(old) +# optimized := with gforce functions that can return lists #5403 +old = options(datatable.verbose=TRUE) +DT = data.table(grp=1:2, x=1:4) +out = "Making each group and running j (GForce TRUE)" +test(2233.45, copy(DT)[, c("y", "z") := .(shift(x, type="lag", n=1), shift(x, type="lead", n=1)), by=grp], data.table(grp=1:2, x=1:4, y=c(NA, NA, 1:2), z=c(3:4, NA, NA)), output=out) +test(2233.46, copy(DT)[, l := shift(x, n=c(0, 0)), by=grp], data.table(grp=1:2, x=1:4, l=list(INT(1, 1), INT(2, 2), INT(3, 3), INT(4, 4))), output=out) +test(2233.47, copy(DT)[, c("l1", "l2") := shift(x, n=c(-1, 1)), by=grp], data.table(grp=1:2, x=1:4, l1=c(3:4,NA,NA), l2=c(NA,NA,1:2)), output=out) +options(old) # support by=.I; #1732 DT = data.table(V1=1:5, V2=3:7, V3=5:1)