Home > Back-end >  Checking whether numbers can be found in a vector consecutively
Checking whether numbers can be found in a vector consecutively

Time:06-15

I have data as follows:

avector <- c(1,2,3,4,5)
num1 <- 1
num2 <- 2
num3 <- 3

num1%in%avector & num2%in%avector
# TRUE

I would like to write a similar line of code that is only TRUE if the numbers can be found in the avector consecutively.

Desired output:

num1%in%avector & num2%in%avector
# TRUE

# Code similar to this:
num1%in%vector & num3%in%vector
# FALSE

EDIT:

This was not included in the original question, but since I got so many answers.

The reason that I was looking for a solution in the form of:

num1%in%vector & num3%in%vector

Is because I was hoping to use it to filter data (see bonus_dat below):

bonus_dat %>%
  filter(lower %in% strata[[1]] & upper %in% strata[[1]])

I have tried to apply the solution by Benson, but without succes:

bonus_dat %>%
  filter((lower %in% strata[[1]] & upper %in% strata[[1]] & (( which(strata[[1]] == lower) - which(strata[[1]] == upper)) == 1)  ))

Therefore a solution that can be used to filter rows has my preference.

DATA:

library(dplyr)
bonus_dat <- structure(list(strata = list(c(0, 25, 100, 500, 1000, 1e 06), 
    c(0, 25, 100, 500, 1000, 1e 06), c(0, 25, 100, 500, 1000, 
    1e 06), c(0, 25, 100, 500, 1000, 1e 06), c(0, 25, 100, 500, 
    1000, 1e 06), c(0, 25, 100, 500, 1000, 1e 06)), lower = c(0L, 
25L, 100L, 500L, 500L, 1000L), upper = c(25L, 100L, 500L, 1000L, 
1000000L, 1000000L), value = c(1,3,4,6,2,1)), class = c("grouped_df", "tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -6L), groups = structure(list(
    upper = c(25L, 100L, 500L, 1000L, 1000000L), .rows = structure(list(
        1L, 2L, 3L, 4L, 5:6), ptype = integer(0), class = c("vctrs_list_of", 
    "vctrs_vctr", "list"))), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -5L), .drop = TRUE))

CodePudding user response:

In base R, you can paste values to make a string and check if it is present:

grepl(paste(num1, num2, sep = ","), paste(avector, collapse = ","))
grepl(paste(num1, num3, sep = ","), paste(avector, collapse = ","))

CodePudding user response:

We can use another expression to check if the difference in position is equal to 1, if it's equal to one, they're consecutive.

(num1 %in% avector & num2 %in% avector) & (abs(which(avector == num2) - which(avector == num1)) == 1)
[1] TRUE

(num1 %in% avector & num3 %in% avector) & (abs(which(avector == num3) - which(avector == num1)) == 1)
[1] FALSE

CodePudding user response:

How about pasting them together and using str_detect? This has the advantage of being easily extensible to an arbitrary number of numbers.

library(stringr)
str_detect(paste0(avector, collapse=""), paste0(c(num1, num2, num3), collapse=""))
[1] TRUE

CodePudding user response:

foo <- function(x) {
  for (i in 1L:(length(x) - 2L)) {
    if (x[i] == num1 && x[i   1L] == num2 && x[i   2L] == num3) return(TRUE)
  }  
}

foo(avector)
# [1] TRUE

CodePudding user response:

avector <- c(1,2,3,4,5)

num1 <- 1
num2 <- 2
num3 <- 3

diff(which(avector %in% c(num1, num2))) == 1
# TRUE

diff(which(avector %in% c(num1, num3))) == 1
# FALSE

or with error handling

avector <- c(1, 2, 3, 4, 5)

num1 <- 1
num2 <- 2
num3 <- 3

num4 <- 6

fun <- function(vec, nums) {
  if (!all(nums %in% avector)) stop("not all numbers are present in the vector")
  diff(which(vec %in% nums)) == 1)
}

fun(avector, c(num1, num2))
# [1] TRUE

fun(avector, c(num1, num3))
# [1] FALSE

fun(avector, c(num1, num4))
# Error in fun(avector, c(num1, num4)) : 
#   not all numbers are present in the vector

CodePudding user response:

You could add an additional AND statement: abs(diff(match(c(x1, x2), vec))) == 1L

is.consec <- function(x1, x2, vec) {
  x1 %in% vec & x2 %in% vec & abs(diff(match(c(x1, x2), vec))) == 1L
}

is.consec(num1, num2, avector)
# [1] TRUE

is.consec(num1, num3, avector)
# [1] FALSE

Defining a custom function is.consec() is not necessary but it makes the codes neater.


The following test returns FALSE because 6 is not included in avector.

is.consec(5, 6, avector)
# [1] FALSE

This method can be easily used to filter data:

bonus_dat %>%
  rowwise() %>% 
  filter(is.consec(lower, upper, strata)) %>%
  ungroup()

# # A tibble: 5 × 4
#   strata    lower   upper value
#   <list>    <int>   <int> <dbl>
# 1 <dbl [6]>     0      25     1
# 2 <dbl [6]>    25     100     3
# 3 <dbl [6]>   100     500     4
# 4 <dbl [6]>   500    1000     6
# 5 <dbl [6]>  1000 1000000     1
  •  Tags:  
  • r
  • Related