Reputation: 509
If I have vectors like these:
vec1 <- c("a", "b", "c")
vec2 <- c("a", "b", "c", "d", "e")
I can use
vec1 %in% vec2
TRUE TRUE TRUE
to determine whether vec1 is contained within vec2. However, I need to respect the relative order, and this approach does not:
vec3 <- c("e", "d", "c", "b", "a")
vec 1 %in% vec3 #should return false because not in abc order
TRUE TRUE TRUE
How can I determine if one vector is contained within another with the same relative order in both vectors? Thanks!
Edit: The vectors are character vectors, but may contain other elements between the ones I care about. For example, I want the following to return TRUE:
vec1 <- c("a", "b", "c")
vec4 <- c("a", "x", "b", "c", "y")
Upvotes: 1
Views: 2195
Reputation: 263481
The match
function returns the ordering of one vector inside another. Then the sequential differences of that result will be strictly positive if and only if the "relative order" you seek is present.
all(vec1 %in% vec4) & all(diff(match(vec1, vec4)) >0 )
[1] TRUE
# also passes the additonal tests
all(vec5 %in% vec7) & all(diff(match(vec5, vec7)) >0 )
#[1] FALSE
all(vec6 %in% vec7) & all(diff(match(vec6, vec7)) >0 )
#[1] TRUE
Upvotes: 1
Reputation: 13591
You can collapse your vector into a regex pattern and use grepl
vec1 <- c("a", "b", "c")
vec2 <- c("a", "b", "c", "d", "e")
grepl(paste(vec1, collapse=".*"), paste(vec2, collapse=""))
# TRUE
vec3 <- c("e", "d", "c", "b", "a")
grepl(paste(vec1, collapse=".*"), paste(vec3, collapse=""))
# FALSE
vec4 <- c("a", "x", "b", "c", "y")
grepl(paste(vec1, collapse=".*"), paste(vec4, collapse=""))
# TRUE
EDIT: Based on G5W's comment, you can add a delimiter in case each element is not a character but might be a short string. The delimiter will break up the entries of your vector
vec5 <- c("a", "b", "c")
vec6 <- c("ab", "c")
vec7 <- c("ab", "e", "c", "d")
grepl(paste(vec5, collapse="-.*"), paste(vec7, collapse="-"))
# FALSE
grepl(paste(vec6, collapse="-.*"), paste(vec7, collapse="-"))
# TRUE
Upvotes: 3