【问题标题】:Identify first match position in a string识别字符串中的第一个匹配位置
【发布时间】:2015-05-21 07:15:03
【问题描述】:

我有一个字符串(“00010000”),需要确定我们在哪个位置看到第一个“1”。 (这告诉我客户在哪个月份活跃)

我有一个如下所示的数据集:

id  <- c(1:5)
seq <- c("00010000","00001000","01000000","10000000","00010000")
df <- data.frame(id,seq)

我想为每个 id 创建一个标识 first_month_active 的新字段。

我可以使用嵌套的 ifelse 函数手动执行此操作:

    df$first_month_active <-
        ifelse(substr(df$seq,1,1)=="1",1,
        ifelse(substr(df$seq,2,2)=="1",2,
        ifelse(substr(df$seq,3,3)=="1",3,       
        ifelse(substr(df$seq,4,4)=="1",4,
        ifelse(substr(df$seq,5,5)=="1",5,99 ))))) 

这给了我想要的结果:

  id  seq        first_position
  1   00010000   4
  2   00001000   5
  3   01000000   2
  4   10000000   1
  5   00010000   4

但是,对于包含 36 个月的数据,这不是一个理想的解决方案。

我想使用带有 ifelse 语句的循环,但是我真的在语法上苦苦挣扎

for (i in 1:36) {
ifelse(substr(df$seq,0+i,0+i)=="1",0+i,
}

任何想法将不胜感激

【问题讨论】:

  • 我认为strsplit 可能会有所帮助。

标签: r loops if-statement substring


【解决方案1】:

或者试试stringi

library(stringi)
stri_locate_first_fixed(df$seq, "1")[, 1]
## [1] 4 5 2 1 4

【讨论】:

    【解决方案2】:

    跳过循环和ifelse:

    9 - nchar(as.numeric(seq))
    ## [1] 4 5 2 1 4
    

    这在您的 data.frame 中不会起作用,因为您强制 seq 隐式分解,所以只需这样做:

    9 - nchar(as.numeric(as.character(df$seq)))
    ## [1] 4 5 2 1 4
    

    编辑:只是为了好玩,因为弗兰克没有将他的评论转化为答案,这里是strsplit 解决方案:

    # from original vector
    sapply(strsplit(seq, "1"), nchar)[1,] + 1
    ## [1] 4 5 2 1 4
    
    # from data.frame
    sapply(strsplit(as.character(df$seq), "1"), nchar)[1,] + 1
    ## [1] 4 5 2 1 4
    

    【讨论】:

    • 第一个对我有用(聪明的解决方案),但那个也很有意义。太棒了!
    • 明显的字符串是“00010000”,但应该注意这可能是双字符,具体取决于编码。在这种情况下,应首先调用strtrim,并给出预期的长度,否则strsplit 可能没有预期的结果。
    • 啊,巧妙的把戏。我在想那个乱七八糟的人sapply(strsplit(c("01001","10000"),"",fixed=TRUE),function(x)which(x=="1")[1])
    【解决方案3】:

    您可以使用gregexpr

    > unlist(gregexpr(pattern=1,seq,fixed=T))
    [1] 4 5 2 1 4
    

    【讨论】:

    • 这个问题是,如果有多个“1”,它会报告两个而不是只报告第一个。使用regexpr 获取第一个。
    【解决方案4】:

    以下可以完成这项工作:

    library(stringr)
    str_locate(pattern ='1',seq)
    

    【讨论】:

      【解决方案5】:

      一些比较:

      library(stringi)
      library(stringr)
      
      seq <- c("00010010","00001000","10000010","10000000","00010000")
      seq2 <- rep(seq, 5e6)
      
      system.time(regexpr("1", seq2))
         user  system elapsed 
         4.78    0.03    4.82
      
      system.time(9-nchar(as.numeric(as.character(seq2))))
         user  system elapsed
         34.89    0.18   35.52
      
      system.time(str_locate(pattern ='1',seq2))
         user  system elapsed 
         6.17    0.21    6.53
      
      system.time(stri_locate_first_fixed(seq2, "1")[, 1])
         user  system elapsed
         1.68    0.15    1.84
      
      system.time(nchar(seq2)-round(log10(as.numeric(seq2))))
         user  system elapsed
         7.67    0.09    7.86
      
      system.time(nchar(sub('1.*', '', seq2))+1)
         user  system elapsed
         14.61    0.11   14.93
      

      【讨论】:

      • 您应该使用microbenchmark 进行计时。比system.time可靠。
      • @Thomas 所有的基准测试都以 为单位,mocrobenchmark 中没有必要。
      • 您可以在regexpr 中添加“fixed = TRUE”以提高性能。
      【解决方案6】:

      另一个,使用log

        nchar(seq)-round(log10(as.numeric(seq)))
      

      【讨论】:

        【解决方案7】:

        另一个使用sub的选项

        nchar(sub('1.*', '', seq))+1
        #[1] 4 5 2 1 4
        

        【讨论】:

          猜你喜欢
          • 2021-09-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-05-24
          • 1970-01-01
          • 2021-04-11
          • 1970-01-01
          相关资源
          最近更新 更多