Рекурсивно применять функцию к объекту по списку аргументов функции

Это вопрос функционального программирования с использованием пакета purrrr. Я точно знаю, как сформулировать этот вопрос, но простой пример покажет, чего я пытаюсь достичь.

У меня есть строка «ABCDEF», и у меня есть список списков с регулярными выражениями и заменами для сопоставления и замены:

subs = list(
    A = list(regex = "A", sub = "a"),
    B = list(regex = "B", sub = "b"),
    C = list(regex = "C", sub = "c")
)

Что я хочу сделать, так это взять строку и применить замены с stringr::str_replace_all одну за другой.

"ABCDEF" %>% 
    str_replace_all(subs$A$regex, subs$A$sub) %>% 
    str_replace_all(subs$B$regex, subs$B$sub) %>% 
    str_replace_all(subs$C$regex, subs$C$sub)

# "abcDEF"

Есть ли расширение reduce или другая функция более высокого порядка, которую я могу использовать для этого? Я знаю, что этого можно добиться, перебирая список замен и изменяя строку на месте, но я ищу функциональную конструкцию.

Так что в идеале должна быть какая-то функция более высокого порядка hof(.init, .x, .f, ...), чтобы я мог рекурсивно применить функцию к строке следующим образом:

hof(.init = "ABCDEF", .x = subs,  ~ str_replace_all(.init, .x$regex, .x$sub)) 

Любая помощь или мысли будут очень признательны!


person Dan    schedule 06.11.2017    source источник
comment
Вы можете найти мурлыканье, эквивалентное чему-то вроде Reduce(function(x, args) chartr(args$regex, args$sub, x), subs, init = "ABCDEF")   -  person alexis_laz    schedule 06.11.2017


Ответы (3)


Мы можем использовать цикл for и назначать результат каждой итерации объекту.

for(i in seq_along(subs)) v1 <- str_replace_all(v1, subs[[i]]$regex, subs[[i]]$sub)
v1
#[1] "abcDEF"

Как упоминал @alexis_laz в комментариях, с purrr аналогичная функция будет

library(purrr)
f1 <- function(x, args) str_replace_all(x, args$regex, args$sub)
reduce(.x = subs, .f = f1, .init = v1)
#[1] "abcDEF"

данные

v1 <- "ABCDEF"
person akrun    schedule 06.11.2017
comment
Спасибо @akrun! На самом деле я пробовал этот метод (создание двоичной функции), но использовал str_replace_all(x, args[["regex"]], args[["sub"]]), но эта ошибка исчезла, что заставило меня подумать, что то, что я пытался, не имеет смысла. - person Dan; 06.11.2017

Вы можете использовать Уменьшить, как вы сами упомянули, как это

Reduce(function(l,r){str_replace_all(l,r$regex, r$sub)},subs,init = "ABCDEF")
person Bertil Baron    schedule 06.11.2017

Это альтернативный подход, который на самом деле не использует шаблоны и замены в формате списка, но сохраняет их как векторы, а затем применяет команду mgsub из пакета qdap.

library(qdap)
library(purrr)

# list of patterns and replacements
subs = list(
  A = list(regex = "A", sub = "a"),
  B = list(regex = "B", sub = "b"),
  C = list(regex = "C", sub = "c")
)

# get patterns and replacements as vectors from the list
subs_t = transpose(subs)
vec_pattern = unlist(subs_t$regex)
vec_replacement = unlist(subs_t$sub)


# apply function
mgsub(vec_pattern, vec_replacement, "ABCDEF")

# [1] "abcDEF"


# function also works with multiple texts
vec_text = c("ABCDEF", "FEDCBA")
mgsub(vec_pattern, vec_replacement, vec_text)

# [1] "abcDEF" "FEDcba"
person AntoniosK    schedule 07.11.2017