Я был почти уверен, что extract
не сработает, но с правильным регулярным выражением. Это на самом деле не намного более "кратко", чем ваше первое решение, но я думаю, что оно, вероятно, настолько кратко, насколько это возможно. (Если вы хотите сократить вещи, подумайте о сворачивании ваших цветов в двухсимвольный символьный вектор, а не в фрейм данных со столбцом списка.)
Проблема с вашим шаблоном регулярных выражений заключается в использовании |
. Вы хотите настроить таргетинг на наборы слов, а не на «x OR y OR z», как это делает ваш шаблон, и поэтому вы получаете только одно совпадение на строку. Для создания коллекции возможных совпадений используйте []
. Включите *
для совпадений "ноль или более". Используя данные вашего примера выше:
library(tidyverse)
colours %>%
mutate(all = map(all, str_c, collapse = " ")) %>%
extract(all, c("cool", "warm", "neutral"),
"([blue green]*) ([red pink yellow gold orange]*) ([ivory brown beige]*)",
remove = F # Include the `all` column.
)
#### OUTPUT ####
# A tibble: 2 x 4
all cool warm neutral
<list> <chr> <chr> <chr>
1 <chr [1]> blue green red pink yellow gold orange ivory brown beige
2 <chr [1]> green red pink orange ivory beige
Основной оговоркой является то, что цветовые категории должны быть в правильном порядке, т. Е. Строка должна содержать группы цветовых слов в порядке cool
→ warm
→ neutral
. Если они случайные, это не сработает. На самом деле, я не думаю, что extract
работал бы больше, если бы цветные слова были случайными, потому что нет способа извлечь отдельные слова и затем объединить их. Вы также потеряете свои столбцы списка - если это важно для вас.
Если порядок не гарантирован, или есть вероятность того, что некоторые слова категории отсутствуют, вы можете сделать что-то вроде следующего. Используя случайную выборку слов категории (обратите внимание, что я опускаю столбцы списка, чтобы вы могли видеть, что происходит):
col_rand <- tribble(
~all,
sample(c('blue','green', 'red', 'pink', 'yellow', 'gold', 'orange', 'ivory', 'brown', 'beige'), 5),
sample(c('green', 'red', 'pink', 'orange', 'ivory', 'beige'), 4)
) %>%
mutate(all = map(all, str_c, collapse = " ") %>% unlist())
#### OUTPUT ####
# A tibble: 2 x 1
all
<chr>
1 blue yellow red beige pink
2 ivory pink beige orange
И со следующими рисунками:
patts <- c(cool = "blue|green",
warm = "red|pink|yellow|gold|orange",
neutral = "ivory|brown|beige"
)
Вы можете сделать что-то вроде следующего, который извлекает совпадения и объединяет их, или возвращает NA
, если совпадений нет:
library(magrittr)
unlist(col_rand$all) %>%
map_dfr(function(x) {str_extract_all(x, patts) %>%
map(function(x) ifelse(length(x) == 0,
NA,
str_c(x, collapse = " ")
)
) %>%
bind_cols()}) %>%
set_colnames(names(patts)) %>% bind_cols(col_rand, .)
#### OUTPUT ####
# A tibble: 2 x 4
all cool warm neutral
<chr> <chr> <chr> <chr>
1 blue yellow red beige pink blue yellow red pink beige
2 ivory pink beige orange NA pink orange ivory beige
Обратите внимание, что библиотека magrittr
загружена для set_colnames
. Если вы загрузите magrittr
после tidyverse
/ tidyr
, вам нужно будет использовать tidyr::extract()
выше, потому что обе библиотеки имеют функцию extract
.