diff --git a/R/data.table.R b/R/data.table.R index 75ea9705f..c1357d992 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -2196,11 +2196,12 @@ setnames <- function(x,old,new) { } else { if (missing(old)) stop("When 'new' is provided, 'old' must be provided too") if (!is.character(new)) stop("'new' is not a character vector") - if (length(new)!=length(old)) stop("'old' is length ",length(old)," but 'new' is length ",length(new)) if (is.numeric(old)) { - tt = old<1L | old>length(x) | is.na(old) + if (length(sgn <- unique(sign(old))) != 1L) + stop("Items of 'old' is numeric but has both +ve and -ve indices.") + tt = abs(old)<1L | abs(old)>length(x) | is.na(old) if (any(tt)) stop("Items of 'old' either NA or outside range [1,",length(x),"]: ",paste(old[tt],collapse=",")) - i = as.integer(old) + i = if (sgn == 1L) as.integer(old) else seq_along(x)[as.integer(old)] if (any(duplicated(i))) stop("Some duplicates exist in 'old': ",paste(i[duplicated(i)],collapse=",")) } else { if (!is.character(old)) stop("'old' is type ",typeof(old)," but should be integer, double or character") @@ -2209,6 +2210,7 @@ setnames <- function(x,old,new) { if (any(is.na(i))) stop("Items of 'old' not found in column names: ",paste(old[is.na(i)],collapse=",")) if (any(tt<-!is.na(chmatch(old,names(x)[-i])))) stop("Some items of 'old' are duplicated (ambiguous) in column names: ",paste(old[tt],collapse=",")) } + if (length(new)!=length(i)) stop("'old' is length ",length(old)," but 'new' is length ",length(new)) } # update the key if the column name being change is in the key m = chmatch(names(x)[i], key(x)) diff --git a/README.md b/README.md index 96eeab36a..0c018d3a1 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ 15. `fread` gains `key` argument, [#590](https://github.com/Rdatatable/data.table/issues/590). + 16. `setnames` accepts negative indices in 'old' argument, [#1443](https://github.com/Rdatatable/data.table/issues/1443). Thanks @richierocks. + #### BUG FIXES 1. Now compiles and runs on IBM AIX gcc. Thanks to Vinh Nguyen for investigation and testing, [#1351](https://github.com/Rdatatable/data.table/issues/1351). diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index e24e57254..0ad090b67 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -7336,6 +7336,11 @@ ans = data.table(id=rep(c("ID_1","ID_2","ID_3"), c(2,1,4)), dens=c(2331,1644,1890,8000,1452,1596,7521)) test(1591, rbindlist(mylist, idcol="id"), ans) +# FR #1443 +DT <- data.table(x = 1:3, y = 4:6, z = 7:9) +test(1592.1, setnames(DT, -5, "bla"), error="Items of 'old'") +test(1592.2, names(setnames(DT, -1, c("m", "n"))), c("x", "m", "n")) + ########################## # TODO: Tests involving GForce functions needs to be run with optimisation level 1 and 2, so that both functions are tested all the time. diff --git a/man/setattr.Rd b/man/setattr.Rd index a6522f0ec..2c7514643 100644 --- a/man/setattr.Rd +++ b/man/setattr.Rd @@ -14,7 +14,7 @@ setnames(x,old,new) \item{name}{ The character attribute name. } \item{value}{ The value to assign to the attribute or \code{NULL} removes the attribute, if present. } \item{old}{ When \code{new} is provided, character names or numeric positions of column names to change. When \code{new} is not provided, the new column names, which must be the same length as the number of columns. See examples. } - \item{new}{ Optional. New column names, the same length as \code{old}. } + \item{new}{ Optional. New column names, must be the same length as columns provided to \code{old} argument. } } \details{ @@ -49,6 +49,9 @@ setnames(DT,2:3,c("D","E")) # multiple setnames(DT,c("a","E"),c("A","F")) # multiple by name (warning if either "a" or "E" is missing) setnames(DT,c("X","Y","Z")) # replace all (length of names must be == ncol(DT)) +DT <- data.table(x = 1:3, y = 4:6, z = 7:9) +setnames(DT, -2, c("a", "b")) # NEW FR #1443, allows -ve indices in 'old' argument + DT = data.table(a=1:3, b=4:6) f = function(...) { # ...