diff --git a/R/rowwiseDT.R b/R/rowwiseDT.R index 1451e58498..f79308bff3 100644 --- a/R/rowwiseDT.R +++ b/R/rowwiseDT.R @@ -2,11 +2,23 @@ rowwiseDT = function(...) { x = substitute(list(...))[-1L] if (is.null(nms <- names(x))) stopf("Must provide at least one column (use `name=`). See ?rowwiseDT for details") + if (length(key_pos <- which(nms == "key" & nzchar(x))) > 0L) { + if (length(key_pos) > 1L) + stopf("Key specified more than once") + if (length(key <- eval(x[[key_pos]], parent.frame())) == 1L) + key = cols_from_csv(key) + x = x[-key_pos] + nms = nms[-key_pos] + } else { + key_pos = 0L + } header_pos = which(nzchar(nms)) if (any(nzchar(x[header_pos]))) stopf("Named arguments must be empty") if (!identical(header_pos, seq_along(header_pos))) stopf("Header must be the first N arguments") + if (key_pos && !key_pos %in% c(1L, length(x) + 1L)) + stopf("Key specification must be either the first or the last argument") header = nms[header_pos] ncols = length(header) body = lapply(x[-header_pos], eval, envir = parent.frame()) @@ -27,5 +39,7 @@ rowwiseDT = function(...) { body = split(body, rep(seq_len(nrows), each = ncols)) ans = rbindlist(body) setnames(ans, header) + if (key_pos) + setkeyv(ans, key) ans } diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 4277ed1533..1c7180b0ab 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -18843,6 +18843,15 @@ test(2282.08, rowwiseDT(A=,B=,1,2,C=,4), error="Header must be the first N argum # evaluate arguments in the correct frame ncols = 1e6 test(2282.09, rowwiseDT(A=,ncols), data.table(A=ncols)) +# tests involving key specification in rowwiseDT +DT = data.table(A=1, B=2, key="B") +test(2282.10, rowwiseDT(key="B", A=, B=, 1, 2), DT) +test(2282.11, rowwiseDT(A=, B=, 1, 2, key="B"), DT) +test(2282.12, rowwiseDT(A=, key=, B=, 1, 2, 3, key="B"), setDT(data.frame(A=1, key=2, B=3), key="B")) +test(2282.13, rowwiseDT(A=, key="B", B=, 1, 2), error="Key specification must be either the first or the last argument") +test(2282.14, rowwiseDT(key="A", key="B", A=, B=, key=, 1, 2, 3), error="Key specified more than once") +# as "" equals to "missing", key = "" means column name (backwards compatible) +test(2282.15, rowwiseDT(A="", B="", key="", 1, 2, 3), setDT(data.frame(A=1, B=2, key=3))) # test 2283 moved tests to optimize.Rraw diff --git a/man/rowwiseDT.Rd b/man/rowwiseDT.Rd index c21f425e3d..3a4f4ef43c 100644 --- a/man/rowwiseDT.Rd +++ b/man/rowwiseDT.Rd @@ -8,7 +8,7 @@ rowwiseDT(...) } \arguments{ - \item{...}{ Arguments that define the structure of a \code{data.table}. The column names come from named arguments (like \code{col=}), which must precede the data. See Examples. } + \item{...}{ Arguments that define the structure of a \code{data.table}. The column names come from named arguments (like \code{col=}), which must precede the data. A \code{key} can also be specified, given it is the first or last argument. See Examples. } } \value{ A \code{data.table}. The default is for each column to return as a vector. However, if any entry has a length that is not one (e.g., \code{list(1, 2)}), the whole column will be converted to a list column. @@ -20,6 +20,7 @@ A \code{data.table}. The default is for each column to return as a vector. Howev rowwiseDT( A=,B=, C=, 1, "a",2:3, - 2, "b",list(5) + 2, "b",list(5), + key = "A" ) }