【发布时间】:2011-08-19 18:34:33
【问题描述】:
假设我有一个字符串s = "bcabca"。
从中获取"aabbcc" 的最简单方法是什么,即对s 中的字母进行排序?
【问题讨论】:
-
如何定义“最简单”?
-
直截了当、自然、最短 :) 例如,在 Haskell 中,您可以说
sort "bcabca",然后得到“aabbcc”。这就是我所说的简单:)
假设我有一个字符串s = "bcabca"。
从中获取"aabbcc" 的最简单方法是什么,即对s 中的字母进行排序?
【问题讨论】:
sort "bcabca",然后得到“aabbcc”。这就是我所说的简单:)
也许不是最简单的答案,但这会奏效:
paste(sort(unlist(strsplit(s, ""))), collapse = "")
或者修改?strsplit的帮助页面中定义的strReverse函数以满足我们的需要。我们称之为 strSort:
strSort <- function(x)
sapply(lapply(strsplit(x, NULL), sort), paste, collapse="")
【讨论】:
stri_flatten而不是paste的变体:stri_flatten(sort(unlist(strsplit(s,""))))
sapply(strsplit(x, NULL), function(x) paste(sort(x), collapse = '') 慢(这已经很慢了)
这是 Chase 解决方案的一个变体,它处理字符串向量并将原始字符串保留为名称。 ...我有机会推广使用 vapply 而不是 sapply :-)
> x=c('hello', 'world', NA, 'a whole sentence')
> vapply(x, function(xi) paste(sort(strsplit(xi, NULL)[[1]]), collapse=''), '')
hello world <NA> a whole sentence
"ehllo" "dlorw" "" " aceeeehlnnostw"
【讨论】:
重新审视这一点,我的旧答案不太好。这是带有base 函数的更好版本:
vapply(strsplit(x, NULL), function(x) paste(sort(x), collapse = ''), '')
基于这个测试向量:
NN = 1000000L
starts = seq(1L, NN, by = 100L)
name =
substring(paste(sample(letters, size = NN, replace = TRUE), collapse = ""),
starts, starts + 99L)
【讨论】:
对于这个问题,最好提及stringi 包。 stri_order 和 stri_sort 函数非常高效,测试时间是上述基本 R 方法的一半。
library(stringi)
## generate 10k random strings of 100 characters each
str <- stri_rand_strings(1e4, 100)
## helper function for vapply()
striHelper <- function(x) stri_c(x[stri_order(x)], collapse = "")
## timings
system.time({
v1 <- vapply(stri_split_boundaries(str, type = "character"), striHelper, "")
})
# user system elapsed
# 0.747 0.000 0.743
system.time({
v2 <- sapply(lapply(strsplit(str, NULL), sort), paste, collapse="")
})
# user system elapsed
# 2.077 0.000 2.068
identical(v1, v2)
# [1] TRUE
【讨论】:
stringi 通过 C 传递东西来加速吗?
tidyverse 用户添加它 stringr::str_order 包装 stri_order 所以当你已经有 stringr 由 tidyverse 加载时,你不需要显式加载另一个包。