Подтвердить что ты не робот

Как проверить, содержит ли вектор n последовательных чисел

Предположим, что мои векторные числа содержат 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), он все равно вернет TRUE, даже если "1" не являются последовательными.

4b9b3361

Ответ 1

Используя diff и rle, что-то вроде этого должно работать:

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

Ответ 2

Бенчмарки!

Я включаю в себя пару моих функций. Не стесняйтесь добавлять свои. Чтобы получить квалификацию, вам нужно написать общую функцию, которая сообщает, если вектор x содержит n или более последовательные числа. Я предоставляю unit test функцию ниже.


Участники:

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

Ответ 3

После diff вы можете проверить any последовательный 1 -

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

Ответ 4

Здесь приятно видеть домашние решения.

Пользователь Carl Witthoft опубликовал функцию, которую он назвал seqle() и поделился ею здесь.

Функция выглядит следующим образом:

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" и искать последовательности, где разница между числами равна двум. Итак, для первого вектора мы ожидаем, что будет обнаружена последовательность 3, 5 и 7.

Попробуйте:

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

$values
[1] 1 2 3 8

Итак, мы можем видеть, что мы имеем последовательность 1 (1), 1 (2), 3 (3, 5, 7) и 1 (8), если положить incr = 2.


Как это работает с второй проблемой ECII? Кажется ОК!

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

$values
[1] -2  5  7

Ответ 5

Простой, но работает

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() работает