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