#r
#r
Вопрос:
Предположим, у меня есть вектор символов
vals <- c("hello","goodbye","junk")
и вектор целей регулярных выражений
targets <- c("(hello|goodbye)","^j","other")
(Я готов оговорить, что каждый элемент в vals
соответствует ровно одному элементу в targets
). Существует ли существующий, эффективный / компактный / векторизованный способ нахождения индекса соответствия каждого элемента в vals
in targets
? ( match
не работает: он соответствует таблице строк, а не регулярным выражениям.) Таким образом, желаемый результат c(1,1,2)
для этого примера. Приветствуются Base-R или tidyverse / stringr
решения.
Комментарии:
1. Это слишком мило?
x <- outer(vals,targets,stringr::str_detect); col(x)[x]
? Я чувствую, что в некоторых случаях это может сломаться.2. Я сейчас нахожусь на своем телефоне, но я думаю, что stringi::stri_match_all_regex должен быть в состоянии это сделать.
Ответ №1:
Одним из подходов было бы задать имена последовательности list
with и stack
для двух столбцов data.frame. NULL
Элементы будут удалены с stack
помощью . Теперь мы извлекаем второй столбец, чтобы получить list
индекс
as.integer(stack(setNames(m, seq_along(m)))[,2])
#[1] 1 1 2
ПРИМЕЧАНИЕ: Вот m
вывод индекса @BenBolker list
из grep
output
Или с помощью tidyverse
library(tidyverse)
crossing(targets, vals) %>%
mutate(ind = group_indices(., targets)) %>%
filter(str_detect(vals, targets)) %>%
pull(ind)
#[1] 1 1 2
Комментарии:
1. на первый взгляд это совершенно загадочно. Я подумаю об этом …
2. @BenBolker Да, вы ищете решение без
lapply
.3. Нет, я просто был в замешательстве — думал, что это должно быть полное решение, и не мог понять, где происходит сопоставление.
Ответ №2:
Лучший способ, который я могу придумать, чтобы сделать это: инвертировать соответствие, то есть: выполнить итерацию по целевым объектам, затем заполнить совпадения в векторе, соответствующем значениям.
## find positions in `vals` that match each target
m <- lapply(targets,grep,x=vals)
## set up response vector
res <- rep(NA,length(vals))
## fill in matching positions for each target
for (i in seq_along(m)) {
res[m[[i]]] <- i
}
Комментарии:
1. Аналогичный фрагмент этой логики, просто заменяющий
grep
наgrepl
—max.col(sapply(targets,grepl,x=vals), "first")
или дажеmax.col(vapply(targets, grepl, x=vals, FUN.VALUE=logical(length(vals))), "first")
поскольку мы знаем тип вывода.
Ответ №3:
Используя str_detect
in stringr
, перебирайте каждое значение, чтобы найти целевой индекс.
library(stringr)
# Data
vals <- c("hello","goodbye","junk")
targets <- c("(hello|goodbye)","^j","other")
# create empty vector to assign matched value later
v <- c()
for (i in 1:length(vals)){
# value to be looked up against target
stg_i <- vals[i]
# min to get first matched target
stg_v <- min(which(str_detect(stg_i, targets)))
# update the value in vector with matched one
v[i] <- stg_v
}
v
[1] 1 1 2