разница между циклами для R и Python - PullRequest
0 голосов
/ 05 октября 2018

Моя функция должна преобразовывать все прописные буквы в данной строке в строчные и наоборот.Я имел обыкновение решать такие проблемы с петлями.Итак, мой код:

mirror_case <- function(x){
   for(i in x){
     ifelse(i==toupper(i),x <- 
       str_replace_all(x,i,tolower(i)),
            ifelse(i==tolower(i),x <- 
       str_replace_all(x,i,toupper(i)),
                  x <- gsub(i,i,x)))}
   return(x)}

Я проверил это на нескольких строках.Иногда это работает, а иногда нет.

> d
[1] "LKJLjlei 33"
> mirror_case(d)
[1] "LKJLjlei 33"

> e
[1] "asddf"
> mirror_case(e)
[1] "ASDDF"

> f
[1] "ASDDF"
> mirror_case(f)
[1] "asddf"

Так что же не так с этой функцией?Я хотел бы не только получить ответ, но и некоторые объяснения, чтобы понять проблему и не возвращаться сюда с подобным вопросом.

Ответы [ 3 ]

0 голосов
/ 05 октября 2018

@ Решению YosiHammer не требуется вызов sapply (который является циклом) для запуска по списку из одного элемента из split.Как показывает @ @ в комментариях, такие как gsub, paste, даже ifelse, toupper() и tolower() являются векторизованными функциями и могут получать несколько элементов за один вызов.

mirror_case <- function(s) {
  chars <- strsplit(s, '')[[1]]         # RETRIEVE THE CHARACTER VECTOR

  mirror_chars <- ifelse(toupper(chars) == chars, tolower(chars), toupper(chars))

  mirror_s = paste(mirror_chars, collapse = "")

  return(mirror_s)
}


mirror_case("LKJLjlei 33")
# [1] "lkjlJLEI 33"

mirror_case("AbCdEfGhIj")
# [1] "aBcDeFgHiJ"
0 голосов
/ 05 октября 2018

Простым решением этой проблемы является использование функции chartr:

chartr("[A-Za-z]", "[a-zA-Z]", "bbBB 122")

Проверьте это онлайн

Функция векторизована:

chartr("[A-Za-z]", "[a-zA-Z]", c("bbBB 122", "QwER 12 bB"))

другой вариант - передать функцию в str_replace_all, но это неоптимально, как видно из тестов.

library(stringr)
str_replace_all(c("bbBB 122", "QwER 12 bB"),
                "[A-Za-z]",
                function(x)
                  ifelse(toupper(x) == x, tolower(x), toupper(x)))

тест:

данные будут100000 10-символьные строки:

dat <- as.vector(
  replicate(1e5,
          paste0(sample(c(LETTERS,
                   letters,
                   " ",
                   as.character(1:9)),
                 10,
                 replace = TRUE),
          collapse = "")
))

head(dat)
#output
"aPJAGOiirN" "FSYN DLYQS" "K7Vzh8qALH" "vQzU96JOVF" "WMmqO1D3Q8" "XdBiTG72zV"

функции, предлагаемые в других сообщениях (не векторизованные):

mirror_case <- function(s) {
  chars <- strsplit(s, '')[[1]]         # RETRIEVE THE CHARACTER VECTOR

  mirror_chars <- ifelse(toupper(chars) == chars, tolower(chars), toupper(chars))

  mirror_s = paste(mirror_chars, collapse = "")

  return(mirror_s)
}

mirror.case <- function(s) {
  # break to characters
  chars <- strsplit(s, '') 
  # apply your ifelse statement to all characters
  mirror_chars <- sapply(chars, function(i) 
    ifelse(toupper(i) == i, tolower(i), toupper(i))) 
  # join back to a string
  mirror_s <- paste(mirror_chars, collapse = "")
  return(mirror_s)
}


library(microbenchmark)

microbenchmark(missuse = chartr("[A-Za-z]", "[a-zA-Z]", dat),
           missuse2 = str_replace_all(dat,
                                      "[A-Za-z]",
                                      function(x)
                                        ifelse(toupper(x) == x, tolower(x), toupper(x))),
           Parfait = lapply(dat, mirror_case),
           YosiHammer = lapply(dat, mirror_case),
           times = 10)

результаты

Unit: milliseconds
       expr          min          lq        mean      median          uq         max neval
    missuse     9.607483    11.05621    18.48764    16.50272    19.06369    39.65646    10
   missuse2 11226.900565 11473.40730 11612.95776 11582.65838 11636.32779 12218.78642    10
    Parfait  1461.056405  1572.58683  1700.75182  1594.43438  1746.08949  2149.49213    10
 YosiHammer  1526.730674  1576.35174  1649.55893  1607.62199  1670.76008  1843.11601    10

, как вы можете видеть chartr метод примерно в 100 раз быстрее, чем другие решения.

Проверить равенство результатов:

all.equal(chartr("[A-Za-z]", "[a-zA-Z]", dat),
          unlist(lapply(dat, mirror_case)))

all.equal(chartr("[A-Za-z]", "[a-zA-Z]", dat),
          unlist(lapply(dat, mirror.case)))

all.equal(chartr("[A-Za-z]", "[a-zA-Z]", dat),
          str_replace_all(dat,
                          "[A-Za-z]",
                          function(x)
                            ifelse(toupper(x) == x, tolower(x), toupper(x))))
0 голосов
/ 05 октября 2018

Строка в R не является такой же последовательностью, как в Python, и ее нельзя просмотреть в цикле for, подобном этому.Сначала вы должны разбить строку на отдельные символы.Попробуйте это:

mirror_case <- function(s) {
  # break to characters
  chars <- strsplit(s, '') 
  # apply your ifelse statement to all characters
  mirror_chars <- sapply(chars, function(i) 
    ifelse(toupper(i) == i, tolower(i), toupper(i))) 
  # join back to a string
  mirror_s <- paste(mirror_chars, collapse = "")
  return(mirror_s)
}

mirror_case("LKJLjlei 33")
# [1] "lkjlJLEI 33"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...