Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@

13. In rare cases, `data.table` failed to expand ALTREP columns when assigning a full column by reference. This could result in the target column getting modified unintentionally if the next call to the data.table was a modification by reference of the source column. E.g. in `DT[, b := as.character(a)]` the string conversion gets deferred and subsequent modification of column `a` would also modify column `b`, [#5400](https://github.com/Rdatatable/data.table/issues/5400). Thanks to @aquasync for the report and Václav Tlapák for the PR.

14. `data.table` function is now more aligned to base R about names of the output when one of its input is a single column matrix object, [#4124](https://github.com/Rdatatable/data.table/issues/4124). Thanks to @PavoDive for reporting. For matrix column objects it will also ensure to return non-duplicated names, [#3193](https://github.com/Rdatatable/data.table/issues/3193).

### NOTES

1. Continued work to remove non-API C functions, [#6180](https://github.com/Rdatatable/data.table/issues/6180). Thanks Ivan Krylov for the PRs and for writing a clear and concise guide about the R API: https://aitap.codeberg.page/R-api/.
Expand Down
9 changes: 7 additions & 2 deletions R/as.data.table.R
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ as.data.table.list = function(x,
n = length(x)
eachnrow = integer(n) # vector of lengths of each column. may not be equal if silent repetition is required.
eachncol = integer(n)
missing.check.names = missing(check.names)
missing.check.names = missing(check.names) || is.null(check.names) # is.null for #3193
if (missing.check.names) check.names = FALSE
origListNames = if (missing(.named)) names(x) else NULL # as.data.table called directly, not from inside data.table() which provides .named, #3854
empty_atomic = FALSE
for (i in seq_len(n)) {
Expand All @@ -142,7 +143,11 @@ as.data.table.list = function(x,
xi = x[[i]] = as.POSIXct(xi)
} else if (is.matrix(xi) || is.data.frame(xi)) {
if (!is.data.table(xi)) {
xi = x[[i]] = as.data.table(xi, keep.rownames=keep.rownames) # we will never allow a matrix to be a column; always unpack the columns
if (is.matrix(xi) && NCOL(xi)<=1L) { # 1 column matrix naming #4124
xi = x[[i]] = c(xi)
} else {
xi = x[[i]] = as.data.table(xi, keep.rownames=keep.rownames) # we will never allow a matrix to be a column; always unpack the columns
}
}
# else avoid dispatching to as.data.table.data.table (which exists and copies)
} else if (is.table(xi)) {
Expand Down
1 change: 1 addition & 0 deletions R/data.table.R
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ data.table = function(..., keep.rownames=FALSE, check.names=FALSE, key=NULL, str
names(x) = nd$vnames
if (length(x)==0L) return( null.data.table() )
if (length(x)==1L && (is.null(x[[1L]]) || (is.list(x[[1L]]) && length(x[[1L]])==0L))) return( null.data.table() ) #48
if (missing(check.names)) check.names = NULL ## inherit missingness #3193
ans = as.data.table.list(x, keep.rownames=keep.rownames, check.names=check.names, .named=nd$.named) # see comments inside as.data.table.list re copies
if (!is.null(key)) {
if (!is.character(key)) stopf("key argument of data.table() must be character")
Expand Down
24 changes: 17 additions & 7 deletions inst/tests/tests.Rraw
Original file line number Diff line number Diff line change
Expand Up @@ -21130,16 +21130,16 @@ class(DF) = c("tbl_df", "tbl", "data.frame")
test(2309.02, key(as.data.table(DF, key="t")), "t")

# data.table keyed with "b"
DT = data.table(a = 1:5, b = 1:5, x = 1:5, key = "b")
test(2309.03, key(as.data.table(DT, key="a")), "a")
test(2309.04, key(as.data.table(DT)), "b")
test(2309.05, key(as.data.table(DT, key=NULL)), NULL)
DT = data.table(a = 1:5, b = 1:5, x = 1:5, key = "b")
test(2309.03, key(as.data.table(DT, key="a")), "a")
test(2309.04, key(as.data.table(DT)), "b")
test(2309.05, key(as.data.table(DT, key=NULL)), NULL)

# non-keyed data.table
DT = data.table(a = 1:5, b = 1:5, x = 1:5)
test(2309.06, key(as.data.table(DT, key="a")), "a")
test(2309.07, key(as.data.table(DT)), NULL)
test(2309.08, key(as.data.table(DT, key=NULL)), NULL)
test(2309.06, key(as.data.table(DT, key="a")), "a")
test(2309.07, key(as.data.table(DT)), NULL)
test(2309.08, key(as.data.table(DT, key=NULL)), NULL)

# as.data.table(x, keep.rownames=TRUE) keeps rownames for class(x)==c("*", "data.frame")
df = structure(list(i = 1:2), class = c("tbl", "data.frame"), row.names = c("a","b"))
Expand Down Expand Up @@ -21215,3 +21215,13 @@ test(2319.1, !is.null(attr(dt_get, ".internal.selfref")))
dt_get0 = data.frame(a = 1:3, b = letters[1:3])
setDT(get0("dt_get0"))
test(2319.2, !is.null(attr(dt_get0, ".internal.selfref")))

# Create a data.table when one vector is transposed doesn't respect the name defined by user #4124
test(2320.1, data.table(a=1:2, b=matrix(1:2)), data.table(a=1:2, b=1:2))
test(2320.2, names(data.table(a=1:2, b=matrix(1:2))), names(data.frame(a=1:2, b=matrix(1:2))))
test(2320.3, data.table(a=1L[0L], b=matrix(1L)[0L]), data.table(a=1L[0L], b=1L[0L])) # length 0
test(2320.4, names(data.table(a=1L[0L], b=matrix(1L)[0L])), names(data.frame(a=1L[0L], b=matrix(1L)[0L])))
# data.table(vector, matrix) can return duplicate column names #3193
is.unq = function(x) length(unique(x)) == length(x)
test(2320.5, is.unq(names(data.table(1:5, matrix(6:15, nrow = 5L)))))
test(2320.6, is.unq(names(data.table(1L[0L], matrix(6:15, nrow=5L)[0L]))))
Loading