From 9580c70dcfcd77dc60b0301cbd7e55c3456958d8 Mon Sep 17 00:00:00 2001 From: sluga Date: Tue, 17 Oct 2023 19:34:04 +0200 Subject: [PATCH 01/20] Mention the 2023 data.table community survey --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 46bbfed1e8..e420ff8ace 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,12 @@ `data.table` provides a high-performance version of [base R](https://www.r-project.org/about.html)'s `data.frame` with syntax and feature enhancements for ease of use, convenience and programming speed. +--- + +**NEW:** Take part in the [data.table 2023 community survey](https://tinyurl.com/datatable-survey/) and help shape the future of the project! The survey closes on **December 1st**. + +--- + ## Why `data.table`? * concise syntax: fast to type, fast to read From 0abcb02ee36556df075eca5ab68c3369b4e17fa7 Mon Sep 17 00:00:00 2001 From: sluga Date: Tue, 2 Apr 2024 20:07:45 +0200 Subject: [PATCH 02/20] Add skip_absent to setcolorder --- R/data.table.R | 9 ++++++++- inst/tests/tests.Rraw | 8 ++++++++ man/setcolorder.Rd | 3 ++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/R/data.table.R b/R/data.table.R index 24eff62d58..fdd39315c8 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -2681,7 +2681,7 @@ setnames = function(x,old,new,skip_absent=FALSE) { invisible(x) } -setcolorder = function(x, neworder=key(x), before=NULL, after=NULL) # before/after #4358 +setcolorder = function(x, neworder=key(x), before=NULL, after=NULL,skip_absent=FALSE) # before/after #4358 { if (is.character(neworder) && anyDuplicated(names(x))) stopf("x has some duplicated column name(s): %s. Please remove or rename the duplicate(s) and try again.", brackify(unique(names(x)[duplicated(names(x))]))) @@ -2689,6 +2689,13 @@ setcolorder = function(x, neworder=key(x), before=NULL, after=NULL) # before/af stopf("Provide either before= or after= but not both") if (length(before)>1L || length(after)>1L) stopf("before=/after= accept a single column name or number, not more than one") + if (!isTRUEorFALSE(skip_absent)) + stopf("skip_absent should be TRUE or FALSE") + if (skip_absent && is.character(neworder)){ + neworder = intersect(neworder, colnames(x)) + } else if (skip_absent && is.numeric(neworder)){ + neworder = intersect(neworder, seq_along(x)) + } neworder = colnamesInt(x, neworder, check_dups=FALSE) # dups are now checked inside Csetcolorder below if (length(before)) neworder = c(setdiff(seq_len(colnamesInt(x, before) - 1L), neworder), neworder) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 24b4f4c60e..f4794b4140 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -1567,6 +1567,14 @@ test(498.03, setcolorder(DT, 1, after=3), data.table(b=2, c=3, a=1)) test(498.04, setcolorder(DT, 3, before=1), data.table(a=1, b=2, c=3)) test(498.05, setcolorder(DT, 1, before=1, after=1), error="Provide either before= or after= but not both") test(498.06, setcolorder(DT, 1, before=1:2), error="before=/after= accept a single column name or number, not more than one") +# skip_absent +test(498.07, setcolorder(DT, skip_absent = 'TRUE'), error = 'TRUE or FALSE') +test(498.08, setcolorder(DT, skip_absent = 1), error = 'TRUE or FALSE') +test(498.09, setcolorder(DT, skip_absent = c(TRUE, FALSE)), error = 'TRUE or FALSE') +test(498.10, setcolorder(DT, c('d', 'c', 'b', 'a')), error = 'non-existing column') +test(498.11, setcolorder(DT, c('d', 'c', 'b', 'a'), skip_absent = TRUE), data.table(c=3, b=2, a=1)) +test(498.12, setcolorder(DT, 4:1), error = 'non-existing column') +test(498.13, setcolorder(DT, 4:1, skip_absent = TRUE), data.table(a=1, b=2, c=3)) # test first group listens to nomatch when j uses join inherited scope. x <- data.table(x=c(1,3,8),x1=10:12, key="x") diff --git a/man/setcolorder.Rd b/man/setcolorder.Rd index e11a24d79c..2fa804d192 100644 --- a/man/setcolorder.Rd +++ b/man/setcolorder.Rd @@ -9,12 +9,13 @@ } \usage{ -setcolorder(x, neworder=key(x), before=NULL, after=NULL) +setcolorder(x, neworder=key(x), before=NULL, after=NULL,skip_absent=FALSE) } \arguments{ \item{x}{ A \code{data.table}. } \item{neworder}{ Character vector of the new column name ordering. May also be column numbers. If \code{length(neworder) < length(x)}, the specified columns are moved in order to the "front" of \code{x}. By default, \code{setcolorder} without a specified \code{neworder} moves the key columns in order to the "front" of \code{x}. } \item{before, after}{ If one of them (not both) was provided with a column name or number, \code{neworder} will be inserted before or after that column. } + \item{skip_absent}{ \code{FALSE} (the default) will throw an error if neworder includes columns not present in \code{x}, \code{TRUE} will quietly drop such columns.} } \details{ To reorder \code{data.table} columns, the idiomatic way is to use \code{setcolorder(x, neworder)}, instead of doing \code{x <- x[, ..neworder]} (or \code{x <- x[, neworder, with=FALSE]}). This is because the latter makes an entire copy of the \code{data.table}, which maybe unnecessary in most situations. \code{setcolorder} also allows column numbers instead of names for \code{neworder} argument, although we recommend using names as a good programming practice. From 9e67be426ff1a015e4b90c73b861ecdab72e882d Mon Sep 17 00:00:00 2001 From: sluga Date: Thu, 11 Apr 2024 00:01:34 +0200 Subject: [PATCH 03/20] Update NEWS --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 4fa8d699b3..b05965e73f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -32,6 +32,8 @@ 8. Computations in `j` can return a matrix or array _if it is one-dimensional_, e.g. a row or column vector, when `j` is a list of columns during grouping, [#783](https://github.com/Rdatatable/data.table/issues/783). Previously a matrix could be provided `DT[, expr, by]` form, but not `DT[, list(expr), by]` form; this resolves that inconsistency. It is still an error to return a "true" array, e.g. a `2x3` matrix. +9. `setcolorder()` gains `skip_absent` to drop columns that aren't present, [#6044](https://github.com/Rdatatable/data.table/pull/6044). Default behavior (`skip_absent=FALSE`) remains unchanged, i.e. unrecognized columns result in an error. Thanks to @sluga for the suggestion and the PR. + ## BUG FIXES 1. `unique()` returns a copy the case when `nrows(x) <= 1` instead of a mutable alias, [#5932](https://github.com/Rdatatable/data.table/pull/5932). This is consistent with existing `unique()` behavior when the input has no duplicates but more than one row. Thanks to @brookslogan for the report and @dshemetov for the fix. From 67979e301f3905e264a4098f9012cc45be6ef042 Mon Sep 17 00:00:00 2001 From: sluga Date: Wed, 17 Apr 2024 20:26:37 +0200 Subject: [PATCH 04/20] Pass skip_absent to colnamesInt --- R/data.table.R | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/R/data.table.R b/R/data.table.R index 5150583b06..bc9971c214 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -2692,14 +2692,8 @@ setcolorder = function(x, neworder=key(x), before=NULL, after=NULL,skip_absent=F stopf("Provide either before= or after= but not both") if (length(before)>1L || length(after)>1L) stopf("before=/after= accept a single column name or number, not more than one") - if (!isTRUEorFALSE(skip_absent)) - stopf("skip_absent should be TRUE or FALSE") - if (skip_absent && is.character(neworder)){ - neworder = intersect(neworder, colnames(x)) - } else if (skip_absent && is.numeric(neworder)){ - neworder = intersect(neworder, seq_along(x)) - } - neworder = colnamesInt(x, neworder, check_dups=FALSE) # dups are now checked inside Csetcolorder below + neworder = colnamesInt(x, neworder, check_dups=FALSE, skip_absent=skip_absent) # dups are now checked inside Csetcolorder below + neworder = setdiff(neworder, 0) # tests 498.11, 498.13 fail w/o this if (length(before)) neworder = c(setdiff(seq_len(colnamesInt(x, before) - 1L), neworder), neworder) if (length(after)) From e13664384fa615fb854934669e8a91fffc157e56 Mon Sep 17 00:00:00 2001 From: sluga Date: Thu, 25 Apr 2024 21:48:56 +0200 Subject: [PATCH 05/20] Revert --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index 549847d5bb..2825f7c359 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,6 @@ `data.table` provides a high-performance version of [base R](https://www.r-project.org/about.html)'s `data.frame` with syntax and feature enhancements for ease of use, convenience and programming speed. ---- - -**NEW:** Take part in the [data.table 2023 community survey](https://tinyurl.com/datatable-survey/) and help shape the future of the project! The survey closes on **December 1st**. - ---- - ## Why `data.table`? * concise syntax: fast to type, fast to read From 420712d83e80381f2d817c19b7465efd8041f850 Mon Sep 17 00:00:00 2001 From: sluga Date: Thu, 25 Apr 2024 21:49:15 +0200 Subject: [PATCH 06/20] Fix --- R/data.table.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/data.table.R b/R/data.table.R index bc9971c214..88e901d2bc 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -2693,7 +2693,7 @@ setcolorder = function(x, neworder=key(x), before=NULL, after=NULL,skip_absent=F if (length(before)>1L || length(after)>1L) stopf("before=/after= accept a single column name or number, not more than one") neworder = colnamesInt(x, neworder, check_dups=FALSE, skip_absent=skip_absent) # dups are now checked inside Csetcolorder below - neworder = setdiff(neworder, 0) # tests 498.11, 498.13 fail w/o this + neworder = neworder[!neworder %in% 0] # tests 498.11, 498.13 fail w/o this if (length(before)) neworder = c(setdiff(seq_len(colnamesInt(x, before) - 1L), neworder), neworder) if (length(after)) From 7672d4736c54dc5fa900af601d3248a0c094a3e0 Mon Sep 17 00:00:00 2001 From: sluga Date: Thu, 25 Apr 2024 21:57:04 +0200 Subject: [PATCH 07/20] Add test --- inst/tests/tests.Rraw | 1 + 1 file changed, 1 insertion(+) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 72ea981ac6..5bc784fbda 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -1593,6 +1593,7 @@ test(498.10, setcolorder(DT, c('d', 'c', 'b', 'a')), error = 'non-existing colum test(498.11, setcolorder(DT, c('d', 'c', 'b', 'a'), skip_absent = TRUE), data.table(c=3, b=2, a=1)) test(498.12, setcolorder(DT, 4:1), error = 'non-existing column') test(498.13, setcolorder(DT, 4:1, skip_absent = TRUE), data.table(a=1, b=2, c=3)) +test(498.14, setcolorder(DT, c(1, 1, 2, 3), skip_absent = TRUE), error = '!=') # test first group listens to nomatch when j uses join inherited scope. x <- data.table(x=c(1,3,8),x1=10:12, key="x") From 54eaebab7d9170ed812ce962a12f890d52d68b6e Mon Sep 17 00:00:00 2001 From: sluga Date: Thu, 25 Apr 2024 21:59:01 +0200 Subject: [PATCH 08/20] Update NEWS --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 2e7b4ce0f0..0ed7c66919 100644 --- a/NEWS.md +++ b/NEWS.md @@ -36,7 +36,7 @@ 10. `measure` now supports user-specified `cols` argument, which can be useful to specify a subset of columns to `melt`, without having to use a regex, [#5063](https://github.com/Rdatatable/data.table/issues/5063). Thanks to @UweBlock and @Henrik-P for reporting, and @tdhock for the PR. -11. `setcolorder()` gains `skip_absent` to drop columns that aren't present, [#6044](https://github.com/Rdatatable/data.table/pull/6044). Default behavior (`skip_absent=FALSE`) remains unchanged, i.e. unrecognized columns result in an error. Thanks to @sluga for the suggestion and the PR. +11. `setcolorder()` gains `skip_absent` to drop columns that aren't present, [#6044, #6068](https://github.com/Rdatatable/data.table/pull/6044). Default behavior (`skip_absent=FALSE`) remains unchanged, i.e. unrecognized columns result in an error. Thanks to @sluga for the suggestion and @sluga & @Nj221102 for the PRs. ## BUG FIXES From f374677e87e71dded676099fc2b2341e45bbd720 Mon Sep 17 00:00:00 2001 From: sluga Date: Thu, 25 Apr 2024 22:34:46 +0200 Subject: [PATCH 09/20] Improve performance --- R/data.table.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/data.table.R b/R/data.table.R index 88e901d2bc..396cd88866 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -2693,7 +2693,7 @@ setcolorder = function(x, neworder=key(x), before=NULL, after=NULL,skip_absent=F if (length(before)>1L || length(after)>1L) stopf("before=/after= accept a single column name or number, not more than one") neworder = colnamesInt(x, neworder, check_dups=FALSE, skip_absent=skip_absent) # dups are now checked inside Csetcolorder below - neworder = neworder[!neworder %in% 0] # tests 498.11, 498.13 fail w/o this + neworder = neworder[neworder != 0] # tests 498.11, 498.13 fail w/o this if (length(before)) neworder = c(setdiff(seq_len(colnamesInt(x, before) - 1L), neworder), neworder) if (length(after)) From b8997bdd22b7f8529563a5f25775bac8902a496e Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Fri, 26 Apr 2024 09:03:31 -0700 Subject: [PATCH 10/20] Update man/setcolorder.Rd --- man/setcolorder.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/setcolorder.Rd b/man/setcolorder.Rd index 2fa804d192..9f41908c8c 100644 --- a/man/setcolorder.Rd +++ b/man/setcolorder.Rd @@ -15,7 +15,7 @@ setcolorder(x, neworder=key(x), before=NULL, after=NULL,skip_absent=FALSE) \item{x}{ A \code{data.table}. } \item{neworder}{ Character vector of the new column name ordering. May also be column numbers. If \code{length(neworder) < length(x)}, the specified columns are moved in order to the "front" of \code{x}. By default, \code{setcolorder} without a specified \code{neworder} moves the key columns in order to the "front" of \code{x}. } \item{before, after}{ If one of them (not both) was provided with a column name or number, \code{neworder} will be inserted before or after that column. } - \item{skip_absent}{ \code{FALSE} (the default) will throw an error if neworder includes columns not present in \code{x}, \code{TRUE} will quietly drop such columns.} + \item{skip_absent}{ Logical, default \code{FALSE}. If \code{TRUE}, no error is thrown if \code{neworder} includes columns not present in \code{x}, which are silently dropped. } } \details{ To reorder \code{data.table} columns, the idiomatic way is to use \code{setcolorder(x, neworder)}, instead of doing \code{x <- x[, ..neworder]} (or \code{x <- x[, neworder, with=FALSE]}). This is because the latter makes an entire copy of the \code{data.table}, which maybe unnecessary in most situations. \code{setcolorder} also allows column numbers instead of names for \code{neworder} argument, although we recommend using names as a good programming practice. From b135a29f9fed9e423f299a12caebbcc7593941e0 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Fri, 26 Apr 2024 09:05:53 -0700 Subject: [PATCH 11/20] style changes --- inst/tests/tests.Rraw | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 5bc784fbda..a4a32f8208 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -1586,14 +1586,14 @@ test(498.04, setcolorder(DT, 3, before=1), data.table(a=1, b=2, c=3)) test(498.05, setcolorder(DT, 1, before=1, after=1), error="Provide either before= or after= but not both") test(498.06, setcolorder(DT, 1, before=1:2), error="before=/after= accept a single column name or number, not more than one") # skip_absent -test(498.07, setcolorder(DT, skip_absent = 'TRUE'), error = 'TRUE or FALSE') -test(498.08, setcolorder(DT, skip_absent = 1), error = 'TRUE or FALSE') -test(498.09, setcolorder(DT, skip_absent = c(TRUE, FALSE)), error = 'TRUE or FALSE') -test(498.10, setcolorder(DT, c('d', 'c', 'b', 'a')), error = 'non-existing column') -test(498.11, setcolorder(DT, c('d', 'c', 'b', 'a'), skip_absent = TRUE), data.table(c=3, b=2, a=1)) -test(498.12, setcolorder(DT, 4:1), error = 'non-existing column') -test(498.13, setcolorder(DT, 4:1, skip_absent = TRUE), data.table(a=1, b=2, c=3)) -test(498.14, setcolorder(DT, c(1, 1, 2, 3), skip_absent = TRUE), error = '!=') +test(498.07, setcolorder(DT, skip_absent='TRUE'), error='TRUE or FALSE') +test(498.08, setcolorder(DT, skip_absent= 1), error='TRUE or FALSE') +test(498.09, setcolorder(DT, skip_absent= c(TRUE, FALSE)), error='TRUE or FALSE') +test(498.10, setcolorder(DT, c('d', 'c', 'b', 'a')), error='non-existing column') +test(498.11, setcolorder(DT, c('d', 'c', 'b', 'a'), skip_absent=TRUE), data.table(c=3, b=2, a=1)) +test(498.12, setcolorder(DT, 4:1), error='non-existing column') +test(498.13, setcolorder(DT, 4:1, skip_absent=TRUE), data.table(a=1, b=2, c=3)) +test(498.14, setcolorder(DT, c(1, 1, 2, 3), skip_absent=TRUE), error='!=') # test first group listens to nomatch when j uses join inherited scope. x <- data.table(x=c(1,3,8),x1=10:12, key="x") From ed9165d53d6d37916dca14d6eb1ad797f4c9f122 Mon Sep 17 00:00:00 2001 From: sluga Date: Sat, 19 Oct 2024 13:20:22 +0200 Subject: [PATCH 12/20] Add tests --- inst/tests/tests.Rraw | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index a4a32f8208..5a6b4df14c 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -1585,15 +1585,18 @@ test(498.03, setcolorder(DT, 1, after=3), data.table(b=2, c=3, a=1)) test(498.04, setcolorder(DT, 3, before=1), data.table(a=1, b=2, c=3)) test(498.05, setcolorder(DT, 1, before=1, after=1), error="Provide either before= or after= but not both") test(498.06, setcolorder(DT, 1, before=1:2), error="before=/after= accept a single column name or number, not more than one") -# skip_absent -test(498.07, setcolorder(DT, skip_absent='TRUE'), error='TRUE or FALSE') -test(498.08, setcolorder(DT, skip_absent= 1), error='TRUE or FALSE') -test(498.09, setcolorder(DT, skip_absent= c(TRUE, FALSE)), error='TRUE or FALSE') -test(498.10, setcolorder(DT, c('d', 'c', 'b', 'a')), error='non-existing column') -test(498.11, setcolorder(DT, c('d', 'c', 'b', 'a'), skip_absent=TRUE), data.table(c=3, b=2, a=1)) -test(498.12, setcolorder(DT, 4:1), error='non-existing column') -test(498.13, setcolorder(DT, 4:1, skip_absent=TRUE), data.table(a=1, b=2, c=3)) -test(498.14, setcolorder(DT, c(1, 1, 2, 3), skip_absent=TRUE), error='!=') +# skip_absent, #6044 +test(498.07, setcolorder(DT, skip_absent = 'TRUE'), error = 'TRUE or FALSE') +test(498.08, setcolorder(DT, skip_absent = 1), error = 'TRUE or FALSE') +test(498.09, setcolorder(DT, skip_absent = c(TRUE, FALSE)), error = 'TRUE or FALSE') +test(498.10, setcolorder(DT, c('d', 'c', 'b', 'a')), error = 'non-existing column') +test(498.11, setcolorder(DT, c('d', 'c', 'b', 'a'), skip_absent = TRUE), data.table(c=3, b=2, a=1)) +test(498.12, setcolorder(DT, 4:1), error = 'non-existing column') +test(498.13, setcolorder(DT, 4:1, skip_absent = TRUE), data.table(a=1, b=2, c=3)) +test(498.14, setcolorder(DT, c(1, 1, 2, 3), skip_absent = TRUE), error = '!=') +## `c` is not dropped +test(498.15, setcolorder(DT, neworder = 'b', skip_absent = TRUE), data.table(b=2, a=1, c=3)) +test(498.16, setcolorder(DT, neworder = c('a', 'b', 'd'), skip_absent = TRUE), data.table(a=1, b=2, c=3)) # test first group listens to nomatch when j uses join inherited scope. x <- data.table(x=c(1,3,8),x1=10:12, key="x") From 1287753729dcd70573a6fbd183244a7f2080e4c1 Mon Sep 17 00:00:00 2001 From: sluga Date: Sat, 19 Oct 2024 13:20:49 +0200 Subject: [PATCH 13/20] Clarify NEWS entry --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 0ed7c66919..d96c157fc9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -36,7 +36,7 @@ 10. `measure` now supports user-specified `cols` argument, which can be useful to specify a subset of columns to `melt`, without having to use a regex, [#5063](https://github.com/Rdatatable/data.table/issues/5063). Thanks to @UweBlock and @Henrik-P for reporting, and @tdhock for the PR. -11. `setcolorder()` gains `skip_absent` to drop columns that aren't present, [#6044, #6068](https://github.com/Rdatatable/data.table/pull/6044). Default behavior (`skip_absent=FALSE`) remains unchanged, i.e. unrecognized columns result in an error. Thanks to @sluga for the suggestion and @sluga & @Nj221102 for the PRs. +11. `setcolorder()` gains `skip_absent` to ignore unrecognized columns (i.e. columns included in `neworder` but not present in the data), [#6044, #6068](https://github.com/Rdatatable/data.table/pull/6044). Default behavior (`skip_absent=FALSE`) remains unchanged, i.e. unrecognized columns result in an error. Thanks to @sluga for the suggestion and @sluga & @Nj221102 for the PRs. ## BUG FIXES From a08ee8e94e9b9dbe5e4aaf5131fa3c29f85a8d5a Mon Sep 17 00:00:00 2001 From: sluga Date: Sat, 19 Oct 2024 13:36:23 +0200 Subject: [PATCH 14/20] Reword --- man/setcolorder.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/setcolorder.Rd b/man/setcolorder.Rd index 9f41908c8c..5d63ffc939 100644 --- a/man/setcolorder.Rd +++ b/man/setcolorder.Rd @@ -15,7 +15,7 @@ setcolorder(x, neworder=key(x), before=NULL, after=NULL,skip_absent=FALSE) \item{x}{ A \code{data.table}. } \item{neworder}{ Character vector of the new column name ordering. May also be column numbers. If \code{length(neworder) < length(x)}, the specified columns are moved in order to the "front" of \code{x}. By default, \code{setcolorder} without a specified \code{neworder} moves the key columns in order to the "front" of \code{x}. } \item{before, after}{ If one of them (not both) was provided with a column name or number, \code{neworder} will be inserted before or after that column. } - \item{skip_absent}{ Logical, default \code{FALSE}. If \code{TRUE}, no error is thrown if \code{neworder} includes columns not present in \code{x}, which are silently dropped. } + \item{skip_absent}{ Logical, default \code{FALSE}. If \code{neworder} includes columns not present in \code{x}, \code{TRUE} will silently ignore them, whereas \code{FALSE} will throw an error. } \details{ To reorder \code{data.table} columns, the idiomatic way is to use \code{setcolorder(x, neworder)}, instead of doing \code{x <- x[, ..neworder]} (or \code{x <- x[, neworder, with=FALSE]}). This is because the latter makes an entire copy of the \code{data.table}, which maybe unnecessary in most situations. \code{setcolorder} also allows column numbers instead of names for \code{neworder} argument, although we recommend using names as a good programming practice. From f9f6a4249ad7c9fa45ecd509e8a843b7a9c61205 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Mon, 2 Dec 2024 21:11:04 -0800 Subject: [PATCH 15/20] data.table style --- inst/tests/tests.Rraw | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index e28962be5a..96e85e14ac 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -1605,17 +1605,17 @@ test(498.04, setcolorder(DT, 3, before=1), data.table(a=1, b=2, c=3)) test(498.05, setcolorder(DT, 1, before=1, after=1), error="Provide either before= or after= but not both") test(498.06, setcolorder(DT, 1, before=1:2), error="before=/after= accept a single column name or number, not more than one") # skip_absent, #6044 -test(498.07, setcolorder(DT, skip_absent = 'TRUE'), error = 'TRUE or FALSE') -test(498.08, setcolorder(DT, skip_absent = 1), error = 'TRUE or FALSE') -test(498.09, setcolorder(DT, skip_absent = c(TRUE, FALSE)), error = 'TRUE or FALSE') -test(498.10, setcolorder(DT, c('d', 'c', 'b', 'a')), error = 'non-existing column') -test(498.11, setcolorder(DT, c('d', 'c', 'b', 'a'), skip_absent = TRUE), data.table(c=3, b=2, a=1)) -test(498.12, setcolorder(DT, 4:1), error = 'non-existing column') -test(498.13, setcolorder(DT, 4:1, skip_absent = TRUE), data.table(a=1, b=2, c=3)) -test(498.14, setcolorder(DT, c(1, 1, 2, 3), skip_absent = TRUE), error = '!=') +test(498.07, setcolorder(DT, skip_absent='TRUE'), error='TRUE or FALSE') +test(498.08, setcolorder(DT, skip_absent=1), error='TRUE or FALSE') +test(498.09, setcolorder(DT, skip_absent=c(TRUE, FALSE)), error='TRUE or FALSE') +test(498.10, setcolorder(DT, c('d', 'c', 'b', 'a')), error='non-existing column') +test(498.11, setcolorder(DT, c('d', 'c', 'b', 'a'), skip_absent=TRUE), data.table(c=3, b=2, a=1)) +test(498.12, setcolorder(DT, 4:1), error='non-existing column') +test(498.13, setcolorder(DT, 4:1, skip_absent=TRUE), data.table(a=1, b=2, c=3)) +test(498.14, setcolorder(DT, c(1, 1, 2, 3), skip_absent=TRUE), error='!=') ## `c` is not dropped -test(498.15, setcolorder(DT, neworder = 'b', skip_absent = TRUE), data.table(b=2, a=1, c=3)) -test(498.16, setcolorder(DT, neworder = c('a', 'b', 'd'), skip_absent = TRUE), data.table(a=1, b=2, c=3)) +test(498.15, setcolorder(DT, neworder='b', skip_absent=TRUE), data.table(b=2, a=1, c=3)) +test(498.16, setcolorder(DT, neworder=c('a', 'b', 'd'), skip_absent=TRUE), data.table(a=1, b=2, c=3)) # test first group listens to nomatch when j uses join inherited scope. x <- data.table(x=c(1,3,8),x1=10:12, key="x") From 5baf988cceaf21f85ab0926025f51a285b05609f Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Mon, 2 Dec 2024 21:13:46 -0800 Subject: [PATCH 16/20] fix NEWS ordering --- NEWS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 00609c5828..ea8f4c4df3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -65,6 +65,8 @@ rowwiseDT( 4. `patterns()` in `melt()` combines correctly with user-defined `cols=`, which can be useful to specify a subset of columns to reshape without having to use a regex, for example `patterns("2", cols=c("y1", "y2"))` will only give `y2` even if there are other columns in the input matching `2`, [#6498](https://github.com/Rdatatable/data.table/issues/6498). Thanks to @hongyuanjia for the report, and to @tdhock for the PR. +5. `setcolorder()` gains `skip_absent` to ignore unrecognized columns (i.e. columns included in `neworder` but not present in the data), [#6044, #6068](https://github.com/Rdatatable/data.table/pull/6044). Default behavior (`skip_absent=FALSE`) remains unchanged, i.e. unrecognized columns result in an error. Thanks to @sluga for the suggestion and @sluga & @Nj221102 for the PRs. + ## BUG FIXES 1. `fwrite()` respects `dec=','` for timestamp columns (`POSIXct` or `nanotime`) with sub-second accuracy, [#6446](https://github.com/Rdatatable/data.table/issues/6446). Thanks @kav2k for pointing out the inconsistency and @MichaelChirico for the PR. @@ -221,8 +223,6 @@ rowwiseDT( e. Displays `integer64` columns correctly by loading {bit64} if needed, [#6224](https://github.com/Rdatatable/data.table/issues/6224). Thanks @renkun-ken for the report and @MichaelChirico for the fix. -11. `setcolorder()` gains `skip_absent` to ignore unrecognized columns (i.e. columns included in `neworder` but not present in the data), [#6044, #6068](https://github.com/Rdatatable/data.table/pull/6044). Default behavior (`skip_absent=FALSE`) remains unchanged, i.e. unrecognized columns result in an error. Thanks to @sluga for the suggestion and @sluga & @Nj221102 for the PRs. - ## BUG FIXES 1. `unique()` returns a copy when `nrows(x) <= 1` instead of a mutable alias, [#5932](https://github.com/Rdatatable/data.table/pull/5932). This is consistent with existing `unique()` behavior when the input has no duplicates but more than one row. Thanks to @brookslogan for the report and @dshemetov for the fix. From 9005d71c9c273c0921a46bdf6cc44af4814af498 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Mon, 2 Dec 2024 21:16:07 -0800 Subject: [PATCH 17/20] missing '}' in Rd --- man/setcolorder.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/setcolorder.Rd b/man/setcolorder.Rd index 5d63ffc939..94ebddc2a8 100644 --- a/man/setcolorder.Rd +++ b/man/setcolorder.Rd @@ -15,7 +15,7 @@ setcolorder(x, neworder=key(x), before=NULL, after=NULL,skip_absent=FALSE) \item{x}{ A \code{data.table}. } \item{neworder}{ Character vector of the new column name ordering. May also be column numbers. If \code{length(neworder) < length(x)}, the specified columns are moved in order to the "front" of \code{x}. By default, \code{setcolorder} without a specified \code{neworder} moves the key columns in order to the "front" of \code{x}. } \item{before, after}{ If one of them (not both) was provided with a column name or number, \code{neworder} will be inserted before or after that column. } - \item{skip_absent}{ Logical, default \code{FALSE}. If \code{neworder} includes columns not present in \code{x}, \code{TRUE} will silently ignore them, whereas \code{FALSE} will throw an error. + \item{skip_absent}{ Logical, default \code{FALSE}. If \code{neworder} includes columns not present in \code{x}, \code{TRUE} will silently ignore them, whereas \code{FALSE} will throw an error. } } \details{ To reorder \code{data.table} columns, the idiomatic way is to use \code{setcolorder(x, neworder)}, instead of doing \code{x <- x[, ..neworder]} (or \code{x <- x[, neworder, with=FALSE]}). This is because the latter makes an entire copy of the \code{data.table}, which maybe unnecessary in most situations. \code{setcolorder} also allows column numbers instead of names for \code{neworder} argument, although we recommend using names as a good programming practice. From 41535d5e5ebc64bdb16313df8a6f357fc1d45c55 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Mon, 2 Dec 2024 21:16:51 -0800 Subject: [PATCH 18/20] style --- R/data.table.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/data.table.R b/R/data.table.R index 8245f58bef..8fcc0df1ff 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -2736,7 +2736,7 @@ setnames = function(x,old,new,skip_absent=FALSE) { invisible(x) } -setcolorder = function(x, neworder=key(x), before=NULL, after=NULL,skip_absent=FALSE) # before/after #4358 +setcolorder = function(x, neworder=key(x), before=NULL, after=NULL, skip_absent=FALSE) # before/after #4358 { if (is.character(neworder)) check_duplicate_names(x) From 5aba421fc02d647e5171ac35a170b88716cd1384 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Mon, 2 Dec 2024 21:17:23 -0800 Subject: [PATCH 19/20] style --- man/setcolorder.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/setcolorder.Rd b/man/setcolorder.Rd index 94ebddc2a8..010ea9bb51 100644 --- a/man/setcolorder.Rd +++ b/man/setcolorder.Rd @@ -9,7 +9,7 @@ } \usage{ -setcolorder(x, neworder=key(x), before=NULL, after=NULL,skip_absent=FALSE) +setcolorder(x, neworder=key(x), before=NULL, after=NULL, skip_absent=FALSE) } \arguments{ \item{x}{ A \code{data.table}. } From 6ecf673ce44823e92fb48ee83f7d6f310d34c85c Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Mon, 2 Dec 2024 21:27:02 -0800 Subject: [PATCH 20/20] add as author --- DESCRIPTION | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 25a7bd6d37..87a18c7426 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -98,5 +98,6 @@ Authors@R: c( person("Christian", "Wia", role="ctb"), person("Elise", "Maigné", role="ctb"), person("Vincent", "Rocher", role="ctb"), - person("Vijay", "Lulla", role="ctb") + person("Vijay", "Lulla", role="ctb"), + person("Aljaž", "Sluga", role="ctb") )