r - Trying to avoid for loop with sapply (for gsub) -
trying avoid using for loop in following code utilizing sapply, if @ possible. solution loop works fine me, i'm trying learn more r , explore many methods possible.
objective: have vector i , 2 vectors sf (search for) , rp (replace). each i need loop on sf , replace rp match.
i = c("1 6 5 4","7 4 3 1") sf = c("1","2","3") rp = c("one","two","three") funn <- function(i) { (j in seq_along(sf)) = gsub(sf[j],rp[j],i,fixed=t) return(i) } print(funn(i)) result (correct):
[1] "one 6 5 4" "7 4 3 one" i'd same, sapply
#trying avoid loop in fun #funn1 <- function(i) { # = gsub(sf,rp,i,fixed=t) # return(i) #} #print(sapply(i,funn1)) apparently, above commented code not work can first element of sf. first time using sapply, i'm not sure how convert "inner" implicit loop vectorized solution. (even statement - not possible) appreciated!
(i'm aware of mgsub not solution here. keep gsub)
edit: full code packages , belowoffered solutions , timing:
#timing library(microbenchmark) library(functional) = rep(c("1 6 5 4","7 4 3 1"),10000) sf = rep(c("1","2","3"),100) rp = rep(c("one","two","three"),100) #loop funn <- function(i) { (j in seq_along(sf)) = gsub(sf[j],rp[j],i,fixed=t) return(i) } t1 = proc.time() k = funn(i) t2 = proc.time() #print(k) print(microbenchmark(funn(i),times=10)) #mapply t3 = proc.time() mapply(function(u,v) i<<-gsub(u,v,i), sf, rp) t4 = proc.time() #print(i) print(microbenchmark(mapply(function(u,v) i<<-gsub(u,v,i), sf, rp),times=10)) #curry t5 = proc.time() reduce(compose, map(function(u,v) curry(gsub, pattern=u, replacement=v), sf, rp))(i) t6 = proc.time() print(microbenchmark(reduce(compose, map(function(u,v) curry(gsub, pattern=u, replacement=v), sf, rp))(i), times=10)) #4th option n <- length(sf) sf <- setnames(sf,1:n) rp <- setnames(rp,1:n) t7 = proc.time() reduce(function(x,j) gsub(sf[j],rp[j],x,fixed=true),c(list(i),as.list(1:n))) t8 = proc.time() print(microbenchmark(reduce(function(x,j) gsub(sf[j],rp[j],x,fixed=true),c(list(i),as.list(1:n))),times=10)) #usual proc.time print(t2-t1) print(t4-t3) print(t6-t5) print(t8-t7) times:
unit: milliseconds expr min lq mean median uq max neval funn(i) 143 143 149 145 147 165 10 unit: seconds expr min lq mean median uq max neval mapply(function(u, v) <<- gsub(u, v, i), sf, rp) 4.1 4.2 4.4 4.3 4.4 4.9 10 unit: seconds expr min lq mean median uq max neval reduce(compose, map(function(u, v) curry(gsub, pattern = u, replacement = v), sf, rp))(i) 1.6 1.6 1.7 1.7 1.7 1.7 10 unit: milliseconds expr min lq mean median uq max neval reduce(function(x, j) gsub(sf[j], rp[j], x, fixed = true), c(list(i), as.list(1:n))) 141 144 147 145 146 162 10 user system elapsed 0.15 0.00 0.15 user system elapsed 4.49 0.03 4.52 user system elapsed 1.68 0.02 1.68 user system elapsed 0.19 0.00 0.18 so, indeed in case for loop offers best timing , (in opinion) straightforward, simple, , possibly elegant. sticking loop.
thanks all. suggestions accepted , upvoted.
one approach - advantage conciseness not functional programming oriented - since has border effect in modifying i:
mapply(function(u,v) i<<-gsub(u,v,i), sf, rp) #> #[1] "one 6 5 4" "7 4 3 one" or here pure functional programming approach:
library(functional) reduce(compose, map(function(u,v) curry(gsub, pattern=u, replacement=v), sf, rp))(i) #[1] "one 6 5 4" "7 4 3 one" what map(function(u,v) curry(gsub, pattern=u, replacement=v), sf, rp) builds list of function respectively replace 1 one, 2 two, etc. these functions composed , applied i, giving desired result.
Comments
Post a Comment