比 strsplit() 在 R 中将字符串分成两部分的内存效率更高的方法
More memory efficient way than strsplit() to split a string into two in R
我有一个 1.8m 的字符串,我需要将它拆分为 50 个字符的字符串,该字符串出现一次非常接近 1.8m 字符串的开头(大约 10k 个字符)
使用 strsplit()
错误
long_string %>% strsplit(., fifty_character_string)
# Error: C stack usage 9065064 is too close to the limit
我已经尝试用 this method, and this 问题解决特定错误,但到目前为止没有成功。
所以现在我正在研究是否有一种内存效率更高的方法可以将很长的字符串分成两部分。我不太可能需要多次执行此操作,因此我愿意接受可以完成工作的 hacky 方法
以下是执行此操作的不同方法的快速比较:
library(stringi)
library(dplyr)
# get some sample data
set.seed(1)
long_string <- stri_paste(stri_rand_lipsum(10000), collapse = " ")
x <- sample(9000:11000, 1)
split_string <- substr(long_string, x, x + 49)
result <- long_string %>% strsplit(., split_string)
length(unlist(result))
#> [1] 2
substr_fun <- function(str, pattern) {
idx <- regexpr(pattern, str, fixed = TRUE)
res1 <- list(c(substr(str, 1, idx-1), substr(str, idx + attr(idx, "match.length"), nchar(str))))
return(res1)
}
bench::mark(
strsplit_dplyr = long_string %>% strsplit(., split_string),
strsplit_dplyr_fixed = long_string %>% strsplit(., split_string, fixed = TRUE),
strsplit = strsplit(long_string, split_string),
strsplit_fixed = strsplit(long_string, split_string, fixed = TRUE),
stri_split_fixed = stringi::stri_split_fixed(long_string, split_string),
str_split = stringr::str_split(long_string, stringr::fixed(split_string)),
substr_fun = substr_fun(long_string, split_string)
)
#> # A tibble: 7 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 strsplit_dplyr 131ms 134.8ms 7.44 280B 0
#> 2 strsplit_dplyr_fixed 36.6ms 37.6ms 26.5 280B 0
#> 3 strsplit 133ms 133.8ms 7.40 0B 0
#> 4 strsplit_fixed 35.4ms 37.2ms 26.7 0B 0
#> 5 stri_split_fixed 40.7ms 42.5ms 23.6 6.95KB 0
#> 6 str_split 41.6ms 43.1ms 23.4 35.95KB 0
#> 7 substr_fun 13.6ms 14.8ms 67.1 0B 0
就内存使用而言,strsplit
加上选项 fixed = TRUE
并且没有管道开销是最好的解决方案。 stringi
和 stringr
中的实现似乎快了一点,但它们在内存方面的开销甚至比管道的影响更大。
更新
我添加了 @H 1 答案中的方法以及他获取 50 个字符的子字符串用于拆分的方法。唯一的变化是我将它包装在一个函数中并再次添加 fixed = TRUE
因为我认为在这种情况下它更有意义。
如果您不想在字符串中进行多次拆分,那么新函数无疑是赢家!
由于字符串只是被分成两部分,一种有效的方法是结合使用 regexpr()
和 substr()
。
# Generate string (10m char) and pattern
set.seed(10)
long_string <- paste0(sample(letters, 1e+7, replace = TRUE), collapse ="")
x <- sample(9000:11000, 1)
fifty_character_string <- substr(long_string, x, x + 49)
# Find index and split
idx <- regexpr(fifty_character_string, long_string)
res1 <- list(c(substr(long_string, 1, idx-1), substr(long_string, idx + attr(idx, "match.length"), nchar(long_string))))
我有一个 1.8m 的字符串,我需要将它拆分为 50 个字符的字符串,该字符串出现一次非常接近 1.8m 字符串的开头(大约 10k 个字符)
使用 strsplit()
错误
long_string %>% strsplit(., fifty_character_string)
# Error: C stack usage 9065064 is too close to the limit
我已经尝试用 this method, and this 问题解决特定错误,但到目前为止没有成功。
所以现在我正在研究是否有一种内存效率更高的方法可以将很长的字符串分成两部分。我不太可能需要多次执行此操作,因此我愿意接受可以完成工作的 hacky 方法
以下是执行此操作的不同方法的快速比较:
library(stringi)
library(dplyr)
# get some sample data
set.seed(1)
long_string <- stri_paste(stri_rand_lipsum(10000), collapse = " ")
x <- sample(9000:11000, 1)
split_string <- substr(long_string, x, x + 49)
result <- long_string %>% strsplit(., split_string)
length(unlist(result))
#> [1] 2
substr_fun <- function(str, pattern) {
idx <- regexpr(pattern, str, fixed = TRUE)
res1 <- list(c(substr(str, 1, idx-1), substr(str, idx + attr(idx, "match.length"), nchar(str))))
return(res1)
}
bench::mark(
strsplit_dplyr = long_string %>% strsplit(., split_string),
strsplit_dplyr_fixed = long_string %>% strsplit(., split_string, fixed = TRUE),
strsplit = strsplit(long_string, split_string),
strsplit_fixed = strsplit(long_string, split_string, fixed = TRUE),
stri_split_fixed = stringi::stri_split_fixed(long_string, split_string),
str_split = stringr::str_split(long_string, stringr::fixed(split_string)),
substr_fun = substr_fun(long_string, split_string)
)
#> # A tibble: 7 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 strsplit_dplyr 131ms 134.8ms 7.44 280B 0
#> 2 strsplit_dplyr_fixed 36.6ms 37.6ms 26.5 280B 0
#> 3 strsplit 133ms 133.8ms 7.40 0B 0
#> 4 strsplit_fixed 35.4ms 37.2ms 26.7 0B 0
#> 5 stri_split_fixed 40.7ms 42.5ms 23.6 6.95KB 0
#> 6 str_split 41.6ms 43.1ms 23.4 35.95KB 0
#> 7 substr_fun 13.6ms 14.8ms 67.1 0B 0
就内存使用而言,strsplit
加上选项 fixed = TRUE
并且没有管道开销是最好的解决方案。 stringi
和 stringr
中的实现似乎快了一点,但它们在内存方面的开销甚至比管道的影响更大。
更新
我添加了 @H 1 答案中的方法以及他获取 50 个字符的子字符串用于拆分的方法。唯一的变化是我将它包装在一个函数中并再次添加 fixed = TRUE
因为我认为在这种情况下它更有意义。
如果您不想在字符串中进行多次拆分,那么新函数无疑是赢家!
由于字符串只是被分成两部分,一种有效的方法是结合使用 regexpr()
和 substr()
。
# Generate string (10m char) and pattern
set.seed(10)
long_string <- paste0(sample(letters, 1e+7, replace = TRUE), collapse ="")
x <- sample(9000:11000, 1)
fifty_character_string <- substr(long_string, x, x + 49)
# Find index and split
idx <- regexpr(fifty_character_string, long_string)
res1 <- list(c(substr(long_string, 1, idx-1), substr(long_string, idx + attr(idx, "match.length"), nchar(long_string))))