【问题标题】:finding max number of consecutive 1 in a string? [duplicate]查找字符串中连续 1 的最大数量? [复制]
【发布时间】:2013-08-01 20:59:39
【问题描述】:

是否有任何简单的方法可以在字符串中获得最大连续 1 数,例如: "000010011100011111001111111100"?

我当然可以使用循环来实现,但我想避免这种情况,因为我的实际数据集大约有 500,000 条记录。

提前感谢您的帮助。

【问题讨论】:

  • 您尝试过什么(以及来自Stack Overflow question checklist 的其他问题)?
  • 我只尝试使用循环。我有两个循环,一个作为行号的计数器,从数据集的第一行开始一直到最后。另一个循环作为连续 1 数量的计数器。但是效率很低,运行时间也很长。
  • @Thomas,你是对的。我搜索但我没有找到任何东西。我应该使用更好的关键字进行搜索。

标签: r


【解决方案1】:

使用rle 比使用正则表达式更慢且更笨拙。在Thomas' answer 中,当值等于 1 时,您仍然需要提取最大长度。

# make some data
set.seed(21)
N <- 1e5
s <- sample(c("0","1"), N*30, TRUE)
s <- split(s, rep(1:N, each=30))
s <- sapply(s, paste, collapse="")
# Thomas' (complete) answer
r <- function(S) {
  sapply(S, function(x) {
    rl <- rle(as.numeric(strsplit(x,"")[[1]]))
    max(rl$lengths[rl$values==1])
  })
}
# using regular expressions
g <- function(S) sapply(gregexpr("1*",S),
   function(x) max(attr(x,'match.length')))
# timing
system.time(R <- r(s))
#    user  system elapsed 
#    6.41    0.00    6.41
system.time(G <- g(s))
#    user  system elapsed 
#    1.47    0.00    1.46
all.equal(R,G)
# [1] "names for target but not for current"

【讨论】:

  • 感谢@Joshua 的有用回答。
【解决方案2】:

另一种更快的方法不使用rle是用连续的0分割,如下所示:

# following thelatemail's comment, changed '0+' to '[^1]+'
strsplit(x, "[^1]+", perl=TRUE)

然后您可以循环并获取列表中每个元素的最大字符数。这也将比rle 解决方案更快。并且也比@Joshua 的gregexpr 解决方案更快。一些基准测试...

zz <- function(x) {
    vapply(strsplit(x, "[^1]+", perl=TRUE), function(x) max(nchar(x)), 0L)
}

我刚刚意识到@Joshua 的功能也可以通过添加perl=TRUE 和使用vapply 来调整。所以,我也会比较一下。

g2 <- function(S) vapply(gregexpr("1*",S, perl=TRUE),
   function(x) max(attr(x,'match.length')), 0L)

require(microbenchmark)
microbenchmark(t1 <- zz(unname(s)), t2 <- g(unname(s)), t3 <- g2(unname(s)), times=50)
Unit: seconds
                expr      min       lq   median       uq      max neval
 t1 <- zz(unname(s)) 1.187197 1.285065 1.344371 1.497564 1.565481    50
  t2 <- g(unname(s)) 2.154038 2.307953 2.357789 2.417259 2.596787    50
 t3 <- g2(unname(s)) 1.562661 1.854143 1.914597 1.954795 2.203543    50

identical(t1, t2) # [1] TRUE
identical(t1, t3) # [1] TRUE

【讨论】:

  • 不错。在存在01 以外的字符的情况下进行概括,将在strsplit 调用中将"0+" 替换为"[^1]"略微较慢,但可能更安全。
  • 是的,你是对的。但我认为这不会影响性能。
  • 在我的测试中慢了大约 50%。从 0.5s 到 0.75s。
  • 刚刚又做了一次基准测试。使用“0+”需要 1.1 秒,使用“[^1]+”需要 1.22 秒。
  • 非常感谢@Arun 回答问题。
【解决方案3】:

使用rle:

x <- "000010011100011111001111111100"
rr <- rle(strsplit(x,"")[[1]])

Run Length Encoding
  lengths: int [1:9] 4 1 2 3 3 5 2 8 2
  values : chr [1:9] "0" "1" "0" "1" "0" "1" "0" "1" "0"

注意:我删除了 as.numeric 部分,因为它不是必需的。从这里,您可以获得连续 1 的最大计数:

max(rr$lengths[which(rr$values == "1")])
# [1] 8

【讨论】:

  • @Arun - 我认为这应该是一个单独的答案而不是编辑。如果你这样做,我可能会删除我的。
  • @thelatemail,是的,我现在意识到了。单独发布。谢谢。 (Thomas,很抱歉造成混乱)。
  • 如果我想创建一个单独的列,我该怎么做?我尝试为一列执行此操作,并且所有行的值都相同。有什么建议吗?
猜你喜欢
  • 2013-09-17
  • 2019-11-21
  • 1970-01-01
  • 2019-11-23
  • 1970-01-01
  • 2019-01-28
  • 2022-11-02
  • 2015-11-07
  • 1970-01-01
相关资源
最近更新 更多