我有:
vec1 <- c(0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1)
vec2 <- c(1, 1)
我期待:
magicFUN(x = vec1, y = vec2)
[1] 4 7 8
这意味着我希望在另一个向量中包含完整向量的位置。 match
和is.element
无效,因为它们会返回vec2
的每个元素的位置,我需要magicFUN
将完整的vec2
与vec1
相匹配}。
答案 0 :(得分:3)
一般解决方案:
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
for循环将是最快的解决方案(除了使用Rcpp)。见下面的基准:
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
答案 1 :(得分:1)
这是一种方法,但如果vec2
的长度增长,则无法很好地扩展:
which(head(vec1, -1) == vec2[1] & tail(vec1, -1) == vec2[2])
# [1] 4 7 8
修改:更一般的解决方案。
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
答案 2 :(得分:1)
选项是将zoo
包用作:
library(zoo)
which(c(rollapply(vec1, width=2, function(x)all(x==vec2), align = "left"),0)==TRUE)
[1] 4 7 8
已编辑:基于@G.Grothendieck
的反馈:
上述解决方案可以使用length(vec2)
很好地扩展。让我们创建magicFUN
:
magicFUN <- function(vec1, vec2){
which(rollapply(vec1, length(vec2), identical, vec2, align = "left"))
}
magicFUN(vec1, vec2)
#[1] 4 7 8
答案 3 :(得分:1)
以下是使用grep
的另一种方法:
vec1 <- c(0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1)
vec2 <- c(1, 1)
magicFUN = function(x, y){
y_len = length(y)
temp_x = do.call(paste, lapply((y_len-1):0, function(lags){
lag(x, lags)[-(0:(y_len-1))]
}))
temp_y = paste(y, collapse = ' ')
return(grep(temp_y, temp_x, fixed = TRUE))
}
magicFUN(vec1, vec2)
# [1] 4 7 8
答案 4 :(得分:1)
这是尝试使用data.table
包进行矢量化。虽然如果vec2
变得很长,可能会有一些内存问题
library(data.table)
l2 <- length(vec2)
setDT(shift(vec1, 0 : (l2 - 1), type = "lead")
)[, which(rowSums(.SD == vec2[col(.SD)]) == l2)]
## [1] 4 7 8
答案 5 :(得分:0)
一般解决方案,其中a是较长的向量,b是较短的
magicFun <- function(a,b){
la <- length(a)
lb <- length(b)
out <- vector(mode = "numeric", length = la-1)
for(i in 1:(la-lb)) {
out[i] <- ifelse(all(a[i:(i+lb-1)] == b),i,0)
}
out <- out[out != 0]
return(out)
}
magicFun(vec1,vec2)
[1] 4 7 8
答案 6 :(得分:0)
R
中的:
which(sapply(seq_along(vec1),function(x) identical(vec1[x:(x+1)],vec2)))
# [1] 4 7 8
应支持列表和任何数据类型。