如何有效地排序R中字符串中的字符?

Pow*_*ege 9 sorting string performance r

如何有效地对向量中每个字符串的字符进行排序?例如,给定一个字符串向量:

set.seed(1)
strings <- c(do.call(paste0, replicate(4, sample(LETTERS, 10000, TRUE), FALSE)),
do.call(paste0, replicate(3, sample(LETTERS, 10000, TRUE), FALSE)),
do.call(paste0, replicate(2, sample(LETTERS, 10000, TRUE), FALSE)))
Run Code Online (Sandbox Code Playgroud)

我编写了一个函数,该函数将每个字符串分成一个向量,对向量进行排序,然后折叠输出:

sort_cat <- function(strings){
  tmp <- strsplit(strings, split="")
  tmp <- lapply(tmp, sort)
  tmp <- lapply(tmp, paste0, collapse = "")
  tmp <- unlist(tmp)
  return(tmp)
}
sorted_strings <- sort_cat(strings)
Run Code Online (Sandbox Code Playgroud)

但是,我需要将其应用到的字符串向量很长,并且此功能太慢。有没有人对如何提高性能有任何建议?

Car*_*eri 3

您可以通过最小化循环次数来减少时间,并通过使用parallel包进一步做到这一点...我的方法是分割字符串一次,然后在循环中排序并粘贴:

sort_cat <- function(strings){
    tmp <- strsplit(strings, split="")
    tmp <- lapply(tmp, sort)
    tmp <- lapply(tmp, paste0, collapse = "")
    tmp <- unlist(tmp)
    return(tmp)
}

sort_cat2 <- function(strings){
    unlist(mcMap(function(i){
        stri_join(sort(i), collapse = "")
    }, stri_split_regex(strings, "|", omit_empty = TRUE, simplify = F), mc.cores = 8L))
}

> microbenchmark::microbenchmark(
+     old = sort_cat(strings[1:500000]),
+     new = sort_cat2(strings[1:500000]),
+     times = 1
+ )
Unit: seconds
 expr        min         lq       mean     median         uq        max neval
  old 9.62673395 9.62673395 9.62673395 9.62673395 9.62673395 9.62673395     1
  new 5.10547437 5.10547437 5.10547437 5.10547437 5.10547437 5.10547437     1
Run Code Online (Sandbox Code Playgroud)

剃须大概4秒,但还是没那么快......

编辑

好吧,apply在这里使用..策略:

1) 提取字母而不是分割边界 2) 使用结果创建一个矩阵 3) 逐行迭代 4) 排序 5) 连接

您可以避免多个循环和取消列出......忽略:?警告是如果字符串长度不同,您需要删除诸如中的任何空或applyNAi[!is.na(i) && nchar(i) > 0]

sort_cat3 <- function(strings){
    apply(stri_extract_all_regex(strings, "\\p{L}", simplify = TRUE), 1, function(i){
        stri_join(stri_sort(i), collapse = "")
    })
}

> microbenchmark::microbenchmark(
+     old = sort_cat(strings[1:500000]),
+     mapping = sort_cat2(strings[1:500000]),
+     applying = sort_cat3(strings[1:500000]),
+     times = 1
+ )
Unit: seconds
     expr         min          lq        mean      median          uq         max neval
      old 10.35101934 10.35101934 10.35101934 10.35101934 10.35101934 10.35101934     1
  mapping  5.12771799  5.12771799  5.12771799  5.12771799  5.12771799  5.12771799     1
 applying  3.97775326  3.97775326  3.97775326  3.97775326  3.97775326  3.97775326     1
Run Code Online (Sandbox Code Playgroud)

将我们从 10.3 秒缩短到 3.98 秒