diff --git a/NEWS.md b/NEWS.md index b6b525b288..d278665ad8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -192,6 +192,8 @@ 24. `column not found` could incorrectly occur in rare non-equi-join cases, [#3635](https://github.com/Rdatatable/data.table/issues/3635). Thanks to @UweBlock for the report. +25. Complex columns used in `j` during grouping would get mangled, [#3639](https://github.com/Rdatatable/data.table/issues/3639). A related bug prevented assigning complex values using `:=` except for full-column plonks. We still do not support grouping `by` a complex column. Thanks to @eliocamp for filing the bug report. + #### NOTES 1. `rbindlist`'s `use.names="check"` now emits its message for automatic column names (`"V[0-9]+"`) too, [#3484](https://github.com/Rdatatable/data.table/pull/3484). See news item 5 of v1.12.2 below. diff --git a/R/data.table.R b/R/data.table.R index 093cbb3047..fea514aeef 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -889,7 +889,6 @@ replace_order = function(isub, verbose, env) { } # else maybe a call to transform or something which returns a list. av = all.vars(jsub,TRUE) # TRUE fixes bug #1294 which didn't see b in j=fns[[b]](c) use.I = ".I" %chin% av - # browser() if (any(c(".SD","eval","get","mget") %chin% av)) { if (missing(.SDcols)) { # here we need to use 'dupdiff' instead of 'setdiff'. Ex: setdiff(c("x", "x"), NULL) will give 'x'. diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 329d675027..299de72fc8 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -7346,6 +7346,17 @@ test(1540.35, DT1[DT3, lapply(.SD, function(x) x * mul), by=.EACHI, on=c(x="q", y="r"), roll=TRUE], DT1.copy[DT3, lapply(.SD, function(x) x * mul), by=.EACHI, roll=TRUE]) +## more coverage tests for by = .EACHI, on = c(LHS = 'RHS') for numeric type +set.seed(45L) +DT1 = data.table(x=sample(letters[1:3], 15, TRUE), y=sample(6:10, 15, TRUE), + a=sample(100, 15), b=runif(15)) +DT2 = CJ(x=letters[1:3], y=6:10)[, mul := sample(20, 15)][sample(15L, 5L)] +DT3 = rbindlist(list(DT2, list(x="d", y=7L, mul=100L))) +DT3 = DT3[sample(nrow(DT3))] +DT1[ , x_num := match(x, letters) + .1] +DT3[ , x_num := match(x, letters) + .1] +test(1540.36, DT1[DT3[1:3], .(y = x_num), by=.EACHI, on=c(x_num="x_num")], + data.table(x_num = c(3.1, 4.1, 3.1), y = c(2.1, NA, NA))) # to do: add tests for := @@ -15265,6 +15276,28 @@ test(2064.1, x[i, class(date), verbose=TRUE], 'Date', test(2064.2, i[x, class(date), verbose=TRUE], 'Date', output="Coerced integer column i.date to type double for join to match type of x.date") +# complex values in grouping, #3639 +set.seed(42) +DT = CJ(x = 1:10, a = c("a", "b"), b = 1:2) +DT[ , z := complex(rnorm(1:.N), rnorm(1:.N))] +## can simplify this test after #1444 +test(2065.1, all.equal(setkey(copy(DT), NULL), DT[, .(x = x, z = z), by = .(a, b)][order(x, a, b)], ignore.col.order = TRUE)) +test(2065.2, DT[ , base::sum(z), by = a], data.table(a = c('a', 'b'), V1 = c(5.0582228485073+0i, -1.8644229822705+0i))) +test(2065.3, DT[ , sum(Mod(z)), by = b], data.table(b = 1:2, V1 = c(16.031422657932, 13.533483145656))) +## mimicking test 171.3 for coverage +x = data.table(A=c(25L,85L,25L,25L,85L), B=c("a","a","b","c","c"), z=0:4 + (4:0)*1i) +test(2065.4, x[ , data.table(A, z)[A==25, z] + data.table(A, z)[A==85, z], by=B], + data.table(B = c('a', 'c'), V1 = c(1, 7) + (c(7, 1))*1i)) +## mimicking test 771 for coverage +a = data.table(first=1:6, third=c(1i,1,1i,3,3i,4), key="first") +b = data.table(first=c(3,4,4,5,6,7,8), second=1:7, key="first") +test(2065.5, b[ , third:=a[b, third, by=.EACHI]], error="Supplied 2 items to be assigned to 7 items of") +# also works for assignment, as noted in #3690 +DT[ , z_sum := base::sum(z), by = .(a, b)] +test(2065.6, DT[ , z_sum := base::sum(z), by = .(a, b)][1:3, z_sum], + c(1.8791864549242+0i, 3.17903639358309+0i, -4.18868631527035+0i)) +test(2065.7, DT[1L, z_sum := 1i][1L, z_sum], 1i) + ################################### # Add new tests above this line # diff --git a/src/assign.c b/src/assign.c index 3bde57ddb8..d7f5d45785 100644 --- a/src/assign.c +++ b/src/assign.c @@ -943,6 +943,15 @@ const char *memrecycle(SEXP target, SEXP where, int start, int len, SEXP source) td[w-1] = sd[i&mask]; } } break; + case CPLXSXP: { + Rcomplex *td = COMPLEX(target); + const Rcomplex *sd = COMPLEX(source); + for (int i=0; i