如何检查向量是否包含n个连续数字

时间:2013-04-20 07:52:15

标签: r

假设我的矢量数包含c(1,2,3,5,7,8),我希望找到它是否包含3个连续数字,在这种情况下,它们是1,2,3。

numbers = c(1,2,3,5,7,8)
difference = diff(numbers) //The difference output would be 1,1,2,2,1

为了验证我的数字向量中有3个连续的整数,我尝试了以下几点而没什么奖励。

rep(1,2)%in%difference 

上面的代码适用于这种情况,但是如果我的差异向量=(1,2,2,2,1),即使“1”不是连续的,它仍然会返回TRUE。

5 个答案:

答案 0 :(得分:20)

使用diffrle,这样的事情应该有效:

result <- rle(diff(numbers))
any(result$lengths>=2 & result$values==1)
# [1] TRUE

在回答下面的评论时,我之前的回答是专门测试length==3的运行,不包括更长的长度。将==更改为>=会修复此问题。它也适用于涉及负数的运行:

> numbers4 <- c(-2, -1, 0, 5, 7, 8)
> result <- rle(diff(numbers4))
> any(result$lengths>=2 & result$values==1)
[1] TRUE

答案 1 :(得分:13)

基准!

我包括了我的几个功能。随意添加你的。要获得资格,您需要编写一个通用函数,告诉矢量x是否包含n个或更多个连续数字。我在下面提供单元测试功能。


竞争者:

flodel.filter <- function(x, n, incr = 1L) {
  if (n > length(x)) return(FALSE)
  x <- as.integer(x)
  is.cons <- tail(x, -1L) == head(x, -1L) + incr
  any(filter(is.cons, rep(1L, n-1L), sides = 1, method = "convolution") == n-1L,
      na.rm = TRUE)
}

flodel.which <- function(x, n, incr = 1L) {
  is.cons <- tail(x, -1L) == head(x, -1L) + incr
  any(diff(c(0L, which(!is.cons), length(x))) >= n)
}

thelatemail.rle <- function(x, n, incr = 1L) {
  result <- rle(diff(x))
  any(result$lengths >= n-1L  & result$values == incr)
}

improved.rle <- function(x, n, incr = 1L) {
  result <- rle(diff(as.integer(x)) == incr)
  any(result$lengths >= n-1L  & result$values)
}

carl.seqle <- function(x, n, incr = 1) {
  if(!is.numeric(x)) x <- as.numeric(x) 
  z <- length(x)  
  y <- x[-1L] != x[-z] + incr 
  i <- c(which(y | is.na(y)), z) 
  any(diff(c(0L, i)) >= n)
}

单元测试:

check.fun <- function(fun)
  stopifnot(
    fun(c(1,2,3),   3),
   !fun(c(1,2),     3),
   !fun(c(1),       3),
   !fun(c(1,1,1,1), 3),
   !fun(c(1,1,2,2), 3),
    fun(c(1,1,2,3), 3)
  )

check.fun(flodel.filter)
check.fun(flodel.which)
check.fun(thelatemail.rle)
check.fun(improved.rle)
check.fun(carl.seqle)

基准:

x <- sample(1:10, 1000000, replace = TRUE)

library(microbenchmark)
microbenchmark(
  flodel.filter(x, 6),
  flodel.which(x, 6),
  thelatemail.rle(x, 6),
  improved.rle(x, 6),
  carl.seqle(x, 6),
  times = 10)

# Unit: milliseconds
#                   expr       min       lq   median       uq      max neval
#    flodel.filter(x, 6)  96.03966 102.1383 144.9404 160.9698 177.7937    10
#     flodel.which(x, 6) 131.69193 137.7081 140.5211 185.3061 189.1644    10
#  thelatemail.rle(x, 6) 347.79586 353.1015 361.5744 378.3878 469.5869    10
#     improved.rle(x, 6) 199.35402 200.7455 205.2737 246.9670 252.4958    10
#       carl.seqle(x, 6) 213.72756 240.6023 245.2652 254.1725 259.2275    10

答案 2 :(得分:7)

diff之后,您可以检查any个连续1 s -

numbers = c(1,2,3,5,7,8)

difference = diff(numbers) == 1
## [1]  TRUE  TRUE FALSE FALSE  TRUE

## find alteast one consecutive TRUE
any(tail(difference, -1) &
    head(difference, -1))

## [1] TRUE

答案 3 :(得分:6)

很高兴看到本土的解决方案。

Stack Overflow用户Carl Witthoft发布了一个名为seqle()并将其共享here的函数。

该功能如下所示:

seqle <- function(x,incr=1) { 
  if(!is.numeric(x)) x <- as.numeric(x) 
  n <- length(x)  
  y <- x[-1L] != x[-n] + incr 
  i <- c(which(y|is.na(y)),n) 
  list(lengths = diff(c(0L,i)),
       values = x[head(c(0L,i)+1L,-1L)]) 
} 

让我们看看它的实际效果。首先,一些数据:

numbers1 <- c(1, 2, 3, 5, 7, 8)
numbers2 <- c(-2, 2, 3, 5, 6, 7, 8)
numbers3 <- c(1, 2, 2, 2, 1, 2, 3)

现在,输出:

seqle(numbers1)
# $lengths
# [1] 3 1 2
# 
# $values
# [1] 1 5 7
# 
seqle(numbers2)
# $lengths
# [1] 1 2 4
# 
# $values
# [1] -2  2  5
# 
seqle(numbers3)
# $lengths
# [1] 2 1 1 3
# 
# $values
# [1] 1 2 2 1
# 

你特别感兴趣的是结果中的“长度”。

另一个有趣的观点是incr参数。在这里,我们可以将增量设置为“2”,并查找数字之差为2的序列。因此,对于第一个向量,我们期望检测到3,5和7的序列。

让我们试试:

> seqle(numbers1, incr = 2)
$lengths
[1] 1 1 3 1

$values
[1] 1 2 3 8

因此,如果我们设置incr = 2,我们可以看到我们有1(1),1(2),3(3,5,7)和1(8)的序列。


它如何与ECII的第二项挑战合作?好像好了!

> numbers4 <- c(-2, -1, 0, 5, 7, 8)
> seqle(numbers4)
$lengths
[1] 3 1 2

$values
[1] -2  5  7

答案 4 :(得分:4)

简单但有效

numbers = c(-2,2,3,4,5,10,6,7,8)
x1<-c(diff(numbers),0)
x2<-c(0,diff(numbers[-1]),0)
x3<-c(0,diff(numbers[c(-1,-2)]),0,0)

rbind(x1,x2,x3)
colSums(rbind(x1,x2,x3) )==3 #Returns TRUE or FALSE where in the vector the consecutive intervals triplet takes place
[1] FALSE  TRUE  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE

sum(colSums(rbind(x1,x2,x3) )==3) #How many triplets of consecutive intervals occur in the vector
[1] 3

which(colSums(rbind(x1,x2,x3) )==3) #Returns the location of the triplets consecutive integers
[1] 2 3 7

请注意,由于c(-2,-1,0)的工作方式

,因此对于连续的负间隔diff()不起作用