2016-08-04 3 views
12

У меня есть вектор строк, и я хочу заменить одну общую подстроку во всех строках разными подстроками. Я делаю это в R. Например:Как заменить одну подстроку на различные подстроки в R?

input=c("I like fruits","I like you","I like dudes") 
# I need to do something like this 
newStrings=c("You","We","She") 
gsub("I",newStrings,input) 

, так что выход должен выглядеть следующим образом:

"You like fruits" 
"We like you" 
"She like dudes" 

Однако GSUB использует только первую строку в newStrings. Какие-либо предложения? Благодаря

+0

вау так много различных решений для одной проблемы, спасибо всем! – Mohammad

+1

Вы хотите только заменить строки в начале или всюду в строке? Что произойдет, если 'I' появляется несколько раз в строке? –

+0

@ DavidArenburg хорошая точка, я хотел рассмотреть случай, который «я» может появляться где угодно сколько угодно раз. Думаю, мой пример немного вводит в заблуждение. – Mohammad

ответ

14

Вы можете использовать stringr:

stringr::str_replace_all(input, "I" ,newStrings) 

[1] "You like fruits" "We like you"  
[3] "She like dudes" 

или как это было предложено @ Дэвид Arenburg:

stringi::stri_replace_all_fixed(input, "I", newStrings) 

Benchmrk

library(stringi) 
library(stringr) 
library(microbenchmark) 

set.seed(123) 
x <- stri_rand_strings(1e3, 10) 
y <- stri_rand_strings(1e3, 1) 

identical(stringi::stri_replace_all_fixed(x, "I", y), stringr::str_replace_all(x, fixed("I") , y)) 
# [1] TRUE 
identical(stringi::stri_replace_all_fixed(x, "I", y), diag(sapply(y, gsub, pattern = "I", x = x, fixed = TRUE))) 
# [1] TRUE 
identical(stringi::stri_replace_all_fixed(x, "I", y), mapply(gsub, "I", y, x, USE.NAMES = FALSE, fixed = TRUE)) 
# [1] TRUE 

microbenchmark("stingi: " = stringi::stri_replace_all_fixed(x, "I", y), 
       "stringr (optimized): " = stringr::str_replace_all(x, fixed("I") , y), 
       "base::mapply (optimized): " = mapply(gsub, "I", y, x, USE.NAMES = FALSE, fixed = TRUE), 
       "base::sapply (optimized): " = diag(sapply(y, gsub, pattern = "I", x = x, fixed = TRUE))) 

# Unit: microseconds 
#      expr  min   lq  mean  median   uq  max neval cld 
#     stingi:  132.156 137.1165 171.5822 150.3960 194.2345 460.145 100 a 
#  stringr (optimized):  801.894 828.7730 947.1813 912.6095 968.7680 2716.708 100 a 
# base::mapply (optimized): 2827.104 2946.9400 3211.9614 3031.7375 3123.8940 8216.360 100 a 
# base::sapply (optimized): 402349.424 476545.9245 491665.8576 483410.3290 513184.3490 549489.667 100 b 
+1

Ницца! Это более компактно, чем мой ответ. –

+1

@MikeyMike, ваш более общий подход. – Sumedh

+2

Я скоро отредактирую ваше сообщение с помощью теста, если вы не возражаете –

7

mapply() может быть очень полезным в таких случаях:

mapply(sub, "I", newStrings, input, USE.NAMES = FALSE,fixed=T) 
# [1] "You like fruits" "We like you"  "She like dudes" 
+1

Я отредактировал ваш код для (1) 'mapply()', чтобы избежать 'unlist()', (2) 'USE.NAMES = FALSE', чтобы избежать' noname() 'и (3) удалил ненужную анонимную функцию. Теперь все за один звонок. –

+1

Возможно, добавьте 'fixed = TRUE' тоже –

+1

Конечно, бросьте туда тоже! Ха-ха. Я также изменил бы на 'sub()'. Я дам ему понять остальные;) –

2

Вы можете использовать для этого sapply

diag(sapply(newStrings,gsub,pattern="I",x=input)) 
+3

Это было бы ужасно неэффективно, как память, так и производительность –

Смежные вопросы