【问题标题】:Mapping str_detect over a list of strings to detect a second list of strings在字符串列表上映射 str_detect 以检测第二个字符串列表
【发布时间】:2020-03-16 19:51:55
【问题描述】:

获取字符串列表:

strings <- c("ABC_XZY", "qwe_xyz", "XYZ")

我想获取strings 中不包含特定子字符串的所有元素

avoid <- c("ABC")

我能做到

library(stringr)
library(dplyr)
library(purrr)

strings %>% 
   .[!map_lgl(., str_detect, avoid)]
[1] "qwe_xyz" "XYZ"

我想做的是指定几个子字符串

avoid_2 <- c("ABC", "qwe")

然后像以前一样映射列表(不起作用)

strings %>% 
   .[!map_lgl(., str_detect, avoid_2)]
Error: Result 1 must be a single logical, not a logical vector of length 2

我想要的是

[1] "XYZ"

错误很明显 - string 的每个元素正在为 avoid_2 的每个元素生成一个逻辑,总共 2 个逻辑/元素,map_lgl 只能处理一个/元素。

我当然可以单独处理每个子字符串,但我不想 - 我想制作一个子字符串列表

不想要,但确实有效

strings %>%
  .[!map_lgl(., str_detect, "ABC")] %>% 
  .[!map_lgl(., str_detect, "qwe")]

【问题讨论】:

    标签: r purrr stringr


    【解决方案1】:

    除了已经提供的答案之外,值得注意的是 stringr::str_detect 和因此 stringr::str_subset 在它们的 stringpattern 参数上进行了矢量化。这意味着您实际上不需要任何类型的显式迭代(通过循环、lapply 或映射)或调用paste

    library(stringr)
    
    strings <- c("ABC_XZY", "qwe_xyz", "XYZ")
    avoid_2 <- c("ABC", "qwe")
    
    str_subset(strings, avoid_2, negate = TRUE)
    #> Warning in stri_subset_regex(string, pattern, omit_na = TRUE, negate = negate, :
    #> longer object length is not a multiple of shorter object length
    #> [1] "XYZ"
    

    相当烦人的是,这会产生一个警告(这似乎源于对stringi::str_subset_regex 的潜在依赖)。但至关重要的是,它产生了预期的结果。

    【讨论】:

      【解决方案2】:

      一个选项可能是:

      strings[map_lgl(strings, ~ !any(str_detect(., avoid_2)))]
      
      [1] "XYZ"
      

      或者直接做:

      strings[!str_detect(strings, paste(avoid_2, collapse = "|"))]
      

      【讨论】:

        【解决方案3】:

        我们可以遍历 'avoid_2' 模式向量而不是 'string' 因为 'string' 参数是矢量化的(如果模式也与 'string' 具有相同的长度,那么它们都可以传递给元素检查),然后是 reduce 逻辑向量,其中 |negateextract 是“字符串”向量中的元素

        library(dplyr)
        library(stringr)
        library(purrr)
        avoid_2 %>% 
            map(~ str_detect(strings, .x)) %>%
            reduce(`|`) %>% `!` %>% 
            magrittr::extract(strings, .)
        #[1] "XYZ"
        

        或者使用base Rgrep,我们可以通过invert 来获得匹配模式的相反值

        grep(paste(avoid_2, collapse="|"), strings, invert = TRUE, value = TRUE)
        #[1] "XYZ"
        

        【讨论】:

          【解决方案4】:

          您可以将paste所有avoid_2字符串放在一起,collapse他们用“|”。这会创建一个正则表达式,您可以将其输入discardstr_detect

          library(tidyverse)
          
          strings <- c("ABC_XZY", "qwe_xyz", "XYZ")
          avoid_2 <- c("ABC", "qwe")
          
          avoid_2 <- avoid_2 %>% 
             paste(., collapse = "|")
          
          avoid_2
          [1] "ABC|qwe"
          
          #discard any values in strings that are also in avoid_2
          strings %>% 
              discard(str_detect(., avoid_2))
          [1] "XYZ"
          

          【讨论】:

            猜你喜欢
            • 2021-08-15
            • 1970-01-01
            • 2019-04-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-11-16
            • 2018-11-15
            • 2012-01-17
            相关资源
            最近更新 更多