Отображение str_detect на список строк для обнаружения второго списка строк - PullRequest
1 голос
/ 16 марта 2020

Взять список строк:

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

Я бы хотел получить все элементы в strings, которые не содержат заданную c подстроку

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")]

Ответы [ 3 ]

2 голосов
/ 17 марта 2020

В дополнение к уже предоставленным ответам стоит отметить, что stringr::str_detect и, следовательно, stringr::str_subset векторизованы как для аргументов string, так и pattern. Это означает, что вам на самом деле не нужны какие-либо явные итерации (через l oop, lapply или map) или вызовы 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). Важно отметить, что он дает ожидаемые результаты.

1 голос
/ 16 марта 2020

Мы можем l oop по вектору шаблона 'avo_2' вместо 'string', поскольку аргумент 'string' векторизован (если шаблон также имеет ту же длину, что и 'string', тогда они оба могут быть переданы для поэлементной проверки), затем reduce логический вектор с |, negate и extract элементами из вектора 'strings'

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

или с использованием base R с grep, где мы можем передать invert, чтобы получить противоположные значения соответствующего шаблона

grep(paste(avoid_2, collapse="|"), strings, invert = TRUE, value = TRUE)
#[1] "XYZ"
1 голос
/ 16 марта 2020

Один из вариантов может быть:

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

[1] "XYZ"

Или делать напрямую:

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