匹配矢量内的矢量

时间:2018-05-30 20:02:35

标签: r

我有:

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

这意味着我希望在另一个向量中包含完整向量的位置。 matchis.element无效,因为它们会返回vec2的每个元素的位置,我需要magicFUN将完整的vec2vec1相匹配}。

7 个答案:

答案 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

应支持列表和任何数据类型。