这个问题现在已经很老了,但在某些情况下,知道向量是否是连续的实际上非常有用。
两个 OP 答案都很好,但正如 Tommy 所说,公认的答案有一些缺陷。 “序列”是任何“等距的数字序列”,这似乎很自然。这将包括负序列、起始值不是 0 或 1 的序列,等等。
下面给出了一个非常多样化且安全的实现,它解释了
- 负值(-3 到 1)和负方向(3 到 1)
- 没有整数步长的序列(3.5、3.6、3.7...)
- 错误的输入类型,例如无限值、NA 和 NAN 值、data.frames 等。
is.sequence <- function(x, ...)
UseMethod("is.sequence", x)
is.sequence.default <- function(x, ...){
FALSE
}
is.sequence.numeric <- function(x, tol = sqrt(.Machine$double.eps), ...){
if(anyNA(x) || any(is.infinite(x)) || length(x) <= 1 || diff(x[1:2]) == 0)
return(FALSE)
diff(range(diff(x))) <= tol
}
is.sequence.integer <- function(x, ...){
is.sequence.numeric(x, ...)
}
n <- 1236
#Test:
is.sequence(seq(-3, 5, length.out = n))
# TRUE
is.sequence(seq(5, -3, length.out = n))
# TRUE
is.sequence(seq(3.5, 2.5 + n, length.out = n))
# TRUE
is.sequence(LETTERS[1:7])
基本上,实现会检查差异的最大值和最小值是否完全相等。
虽然使用 S3 类方法会使实现稍微复杂一些,但它简化了对错误输入类型的检查,并允许实现其他类。例如,这使得将这个方法扩展为 Date 对象变得很简单,这需要考虑是否只有工作日(或工作日)的序列也是一个序列。
速度对比
此实现非常安全,但使用 S4 类会增加一些开销。对于小长度向量,好处是实现的多样性,而在最坏的情况下它会慢 15% 左右。然而,对于较大的向量,它会稍微快一些,如下面的微基准所示。
请注意,中间时间更适合比较,因为垃圾清理器可能会在基准测试中添加不确定的时间。
ss <- seq(1, 1e6)
microbenchmark::microbenchmark(is.sequential(ss),
is.sequence(ss), #Integer calls numeric, adding a bit of overhead
is.sequence.numeric(ss))
# Unit: milliseconds
# expr min lq mean median uq max neval
# is.sequential(ss) 19.47332 20.02534 21.58227 20.45541 21.23700 66.07200 100
# is.sequence(ss) 16.09662 16.65412 20.52511 17.05360 18.23958 61.23029 100
# is.sequence.numeric(ss) 16.00751 16.72907 19.08717 17.01962 17.66150 55.90792 100