假设我有以下数字向量:
vec = c(1, 2, 3, 5, 7, 8, 9, 10, 11, 12)
Run Code Online (Sandbox Code Playgroud)
我正在寻找一个函数,它将创建一个字符串,以人类的方式总结数字列表,即
"1-3, 5, 7-12"
Run Code Online (Sandbox Code Playgroud)
我怎么能在R中这样做?
ale*_*laz 28
添加另一种替代方法,您可以使用deparseing方法.例如:
deparse(c(1L, 2L, 3L))
#[1] "1:3"
Run Code Online (Sandbox Code Playgroud)
利用as.character"deparse"给定的"列表"作为输入,我们可以使用:
as.character(split(as.integer(vec), cumsum(c(TRUE, diff(vec) != 1))))
#[1] "1:3" "5" "7:12"
toString(gsub(":", "-", .Last.value))
#[1] "1-3, 5, 7-12"
Run Code Online (Sandbox Code Playgroud)
tal*_*lat 21
我假设矢量按照示例中的顺序排序.如果不vec <- sort(vec)事先使用.
编辑注:@DavidArenburg发现一个错误在我原来的答案在c(min(x), x)实际上应该是c(0, x).既然我们现在知道我们总是需要首先添加一个0,我们可以省略创建的第一步x并"动态"执行.现在编辑原始答案和其他选项以反映(您可以检查原始帖子的编辑历史记录).谢谢大卫!
关于调用的注释unname:我曾经unname(sapply(...))确保结果向量没有被命名,否则它将被命名为0:(n-1)其中n等于长度new_vec.正如@Tensibai在评论中正确指出的那样,如果最终目的是生成由运行产生的长度为1的字符向量,则无关紧要,toString(new_vec)因为toString无论如何都将省略向量名称.
一个选项(可能不是最短的)将是:
new_vec <- unname(sapply(split(vec, c(0, cumsum(diff(vec) > 1))), function(y) {
if(length(y) == 1) y else paste0(head(y, 1), "-", tail(y, 1))
}))
Run Code Online (Sandbox Code Playgroud)
结果:
new_vec
#[1] "1-3" "5" "7-12"
toString(new_vec)
#[1] "1-3, 5, 7-12"
Run Code Online (Sandbox Code Playgroud)
感谢@ Zelazny7,可以使用以下range功能缩短它:
new_vec <- unname(sapply(split(vec, c(0, cumsum(diff(vec) > 1))), function(y) {
paste(unique(range(y)), collapse='-')
}))
Run Code Online (Sandbox Code Playgroud)
感谢@DavidArenburg,可以通过使用tapply而不是sapply+ 来进一步缩短它split:
new_vec <- unname(tapply(vec, c(0, cumsum(diff(vec) > 1)), function(y) {
paste(unique(range(y)), collapse = "-")
}))
Run Code Online (Sandbox Code Playgroud)
编辑:我首先通过对矢量进行排序来加快docendo的代码,所以现在它们实际上处于平等地位.
我还添加了亚历克西斯的方法.
readable_integers <- function(integers)
{
integers <- sort(unique(integers))
group <- cumsum(c(0, diff(integers)) != 1)
paste0(vapply(split(integers, group),
function(x){
if (length(x) == 1) as.character(x)
else paste0(range(x), collapse = "-")
},
character(1)),
collapse = "; ")
}
library(microbenchmark)
vec = c(1, 2, 3, 5, 7, 8, 9, 10, 11, 12)
microbenchmark(
docendo = {vec <- sort(vec)
x <- cumsum(diff(vec) > 1)
toString(tapply(vec, c(min(x), x), function(y) paste(unique(range(y)), )collapse = "-"))
},
Benjamin = readable_integers(vec),
alexis = {vec <- sort(vec)
as.character(split(as.integer(vec), cumsum(c(TRUE, diff(vec) != 1))))
toString(gsub(":", "-", .Last.value))}
)
Unit: microseconds
expr min lq mean median uq max neval
docendo 205.273 220.3755 230.3134 228.293 235.4780 467.142 100
Benjamin 121.991 128.4420 135.5302 133.574 143.3980 161.286 100
alexis 121.698 128.0030 137.0374 136.507 143.3975 169.790 100
set.seed(pi)
vec = sample(1:1000, 900)
set.seed(pi)
vec = sample(1:1000, 900)
microbenchmark(
docendo = {vec <- sort(vec)
x <- cumsum(diff(vec) > 1)
toString(tapply(sort(vec), c(min(x), x), function(y) paste(unique(range(y)), collapse = "-")))
},
Benjamin = readable_integers(vec),
alexis = {vec <- sort(vec)
as.character(split(as.integer(vec), cumsum(c(TRUE, diff(vec) != 1))))
toString(gsub(":", "-", .Last.value))}
)
Unit: microseconds
expr min lq mean median uq max neval
docendo 1307.294 1353.7735 1420.3088 1379.7265 1427.8190 2554.473 100
Benjamin 615.525 626.8155 661.2513 638.8385 665.3765 1676.493 100
alexis 799.684 808.3355 866.1516 820.0650 833.2615 1974.138 100
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
842 次 |
| 最近记录: |