Skip to content

Commit 427d596

Browse files
author
maechler
committed
diff(<matrix-alike>, lag, diff.) |-> matrix also when lag*diff. > nrow(.)
git-svn-id: https://svn.r-project.org/R/trunk@89070 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent f55ea99 commit 427d596

File tree

6 files changed

+34
-7
lines changed

6 files changed

+34
-7
lines changed

doc/NEWS.Rd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,10 @@
385385
\item \code{all.equal(obj, simple, check.class=FALSE)} now is true, also
386386
when \code{simple} is a bare atomic vector and \code{obj} has a simple
387387
class, fixing the first part of \PR{18971} thanks to \I{Jan Gorecki}.
388+
389+
\item \code{diff(m, lag, dif)} for matrix \code{m} now still returns
390+
matrices, also when \code{lag * dif > nrow(m)} (\PR{18972}, thanks to
391+
\I{Mikael Jagan}).
388392
}
389393
}
390394
}

src/library/base/R/dates.R

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ seq.Date <- function(from, to, by, length.out = NULL, along.with = NULL, ...)
274274
if(nby2 > 2L || nby2 < 1L)
275275
stop("invalid 'by' string")
276276
bys <- c("days", "weeks", "months", "quarters", "years")
277-
valid <- pmatch(by2[nby2], bys)
277+
valid <- pmatch(by2[nby2], bys)
278278
if(is.na(valid)) stop("invalid string for 'by'")
279279
by <- bys[valid] # had *partial* match
280280
if(valid > 2L) { # seq.POSIXt handles the logic for non-arithmetic cases
@@ -436,8 +436,10 @@ diff.Date <- function (x, lag = 1L, differences = 1L, ...)
436436
xlen <- if (ismat) dim(x)[1L] else length(x)
437437
if (length(lag) != 1L || length(differences) > 1L || lag < 1L || differences < 1L)
438438
stop("'lag' and 'differences' must be integers >= 1")
439-
if (lag * differences >= xlen)
440-
return(.difftime(numeric(), units="days"))
439+
if (lag * differences >= xlen) {
440+
x0 <- if(ismat) x[0L, , drop = FALSE] else x[0L]
441+
return(x0 - x0) # '-' |-> "difftime"
442+
}
441443
r <- x
442444
i1 <- -seq_len(lag)
443445
if (ismat)

src/library/base/R/datetime.R

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1382,7 +1382,10 @@ diff.POSIXt <- function (x, lag = 1L, differences = 1L, ...)
13821382
xlen <- if (ismat) dim(x)[1L] else length(r)
13831383
if (length(lag) != 1L || length(differences) > 1L || lag < 1L || differences < 1L)
13841384
stop("'lag' and 'differences' must be integers >= 1")
1385-
if (lag * differences >= xlen) return(.difftime(numeric(), "secs"))
1385+
if (lag * differences >= xlen) {
1386+
x0 <- if(ismat) x[0L, , drop = FALSE] else x[0L]
1387+
return(x0 - x0) # '-' |-> "difftime"
1388+
}
13861389
i1 <- -seq_len(lag)
13871390
if (ismat)
13881391
for (i in seq_len(differences))

src/library/base/R/diff.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# File src/library/base/R/diff.R
22
# Part of the R package, https://www.R-project.org
33
#
4-
# Copyright (C) 1995-2013 The R Core Team
4+
# Copyright (C) 1995-2025 The R Core Team
55
#
66
# This program is free software; you can redistribute it and/or modify
77
# it under the terms of the GNU General Public License as published by
@@ -26,7 +26,7 @@ diff.default <- function(x, lag = 1L, differences = 1L, ...)
2626
lag < 1L || differences < 1L)
2727
stop("'lag' and 'differences' must be integers >= 1")
2828
if (lag * differences >= xlen)
29-
return(x[0L]) # empty, but of proper mode
29+
return( if(ismat) x[0L, , drop = FALSE] else x[0L] ) # empty, but of proper mode
3030
r <- unclass(x) # don't want class-specific subset methods
3131
i1 <- -seq_len(lag)
3232
if (ismat)

src/library/stats/R/ts.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,8 @@ diff.ts <- function (x, lag = 1, differences = 1, ...)
264264
{
265265
if (lag < 1 || differences < 1)
266266
stop("bad value for 'lag' or 'differences'")
267-
if (lag * differences >= NROW(x)) return(x[0L])
267+
if (lag * differences >= NROW(x))
268+
return(if(is.matrix(x)) x[0L, , drop = FALSE] else x[0L])
268269
## <FIXME>
269270
## lag() and its default method are defined in package ts, so we
270271
## need to provide our own implementation.

tests/reg-tests-1e.R

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2371,6 +2371,23 @@ stopifnot(exprs = {
23712371
## 'check.class' was not passed downstream in R <= 4.5.2
23722372

23732373

2374+
## diff(x=<m-by-n>, l, d) dropped dimensions when l*d >= m
2375+
m <- provideDimnames(matrix(0, 10L, 1L))
2376+
names(dimnames(m)) <- c("row", "col")
2377+
.difftime1 <- .difftime # diff() shouldn't hard code units="days"
2378+
formals(.difftime1)$units <- "secs"
2379+
##' list_(a, b, cc) creates a *named* list using the actual arguments' names
2380+
list_ <- function(...) `names<-`(list(...), vapply(sys.call()[-1L], as.character, ""))
2381+
L <- lapply(list_(identity, ts, .Date, .POSIXct, .difftime1),
2382+
\(fn) { fnm0 <- (fnm <- fn(m))[0L, , drop = FALSE]
2383+
list(f0 = fnm0, f = diff(fnm, lag = 2L, differences = 5L)) })
2384+
str(L, give.attr=FALSE) # now 0 x 1 matrices
2385+
vapply(L, \(.) identical(.$f0, .$f), NA) # where all FALSE; now not all TRUE
2386+
stopifnot( print(
2387+
vapply(L, \(.) identical(.$f0 - .$f0, .$f), NA) ) )
2388+
## where all FALSE : diff(fnm, 2,5) was not a matrix
2389+
2390+
23742391

23752392
## keep at end
23762393
rbind(last = proc.time() - .pt,

0 commit comments

Comments
 (0)