I have:
vec1 <- c(0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1)
vec2 <- c(1, 1)
I expect:
magicFUN(x = vec1, y = vec2)
[1] 4 7 8
That means that I want the position of a complete vector inside another vector. match
and is.element
were not useful because they return the position of each element of vec2
and I need that magicFUN
matches the complete vec2
into vec1
.
In case of vectors, the operator “==” is overloaded to find the result quickly.
C++ Vector Library - operator== Function The C++ function std::vector::operator== tests whether two vectors are equal or not. Operator == first checks the size of both container, if sizes are same then it compares elements sequentially and comparison stops at first mismatch.
vector::pop_back()() pop_back() function is used to pop or remove elements from a vector from the back. The value is removed from the vector from the end, and the container size is decreased by 1.
A general solution:
magicFUN <- function(vec1, vec2) {
if(length(vec2) > length(vec1)) stop("vec 2 should be shorter")
len <- length(vec1) - length(vec2) + 1
out <- vector(mode = "logical", length=len)
for(i in 1:len) {
out[i] <- identical(vec2, vec1[i:(i+length(vec2)-1)])
}
return(which(out))
}
vec1 <- c(0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1)
vec2 <- c(1, 1)
magicFUN(vec1, vec2)
[1] 4 7 8
A for loop will be the fastest solution (besides using Rcpp). See benchmarks below:
magicFUN <- function(vec1, vec2) {
if(length(vec2) > length(vec1)) stop("vec 2 should be shorter")
len <- length(vec1) - length(vec2) + 1
out <- vector(mode = "logical", length=len)
for(i in 1:len) {
out[i] <- identical(vec2, vec1[i:(i+length(vec2)-1)])
}
return(which(out))
}
magicFUN2 <- function(vec1, vec2){
l1 <- length(vec1)
l2 <- length(vec2)
which(colSums(sapply(1:(l1-l2), function(i) vec1[i:(i+l2-1)]) == vec2) == l2)
}
magicFUN3 <- function(vec1, vec2){
which(c(zoo::rollapply(vec1, width=length(vec2),
function(x)all(x==vec2), align = "left"),rep(FALSE,length(vec2)-1))==TRUE)
}
library(microbenchmark)
microbenchmark(magicFUN(vec1, vec2), magicFUN2(vec1, vec2), magicFUN3(vec1, vec2))
Unit: milliseconds
expr min lq mean median uq max neval cld
magicFUN(vec1, vec2) 6.083572 6.575844 7.292443 6.878016 7.421208 13.35746 100 a
magicFUN2(vec1, vec2) 8.289640 8.976736 11.007967 9.338644 9.951492 139.68886 100 a
magicFUN3(vec1, vec2) 39.131268 42.369479 46.303722 44.203563 45.053252 172.46151 100 b
Here is one way, but wouldn't scale well, if length of vec2
grow:
which(head(vec1, -1) == vec2[1] & tail(vec1, -1) == vec2[2])
# [1] 4 7 8
Edit: More general solution.
magicFUN <- function(vec1, vec2){
l1 <- length(vec1)
l2 <- length(vec2)
which(colSums(sapply(1:(l1-l2), function(i) vec1[i:(i+l2-1)]) == vec2) == l2)
}
magicFUN(vec1, vec2)
# [1] 4 7 8
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With