首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >R中的顺序引文编号:用连字符分隔数字,如果顺序-如果不加逗号

R中的顺序引文编号:用连字符分隔数字,如果顺序-如果不加逗号
EN

Stack Overflow用户
提问于 2017-08-09 11:28:18
回答 4查看 696关注 0票数 9

我想为R中的一个数字生成序贯引文号,如果数字是连续的,数字应该用连字符分隔。否则,数字将用逗号分隔。例如,数字1, 2, 3, 5, 6, 8, 9, 10, 11 and 13应该以1-3,5,6,8-11,13的形式出现。

这个问题是以前为c#回答,我编写了一个适用于R的函数,但是这个函数可以改进。我把这个问题作为其他可能有类似需要的人的参考。如果你发现R类似的问题(我没有),请投票结束,我将删除这个问题。

下面的功能不是很优雅,但似乎是做好了这项工作。如何使函数更短、更优雅?

代码语言:javascript
运行
复制
x <- c(1,2,3,5,6,8,9,10,11,13)

library(zoo) ## the function requires zoo::na.approx function 

##' @title Generate hyphenated sequential citation from an integer vector
##' @param x integer vector giving citation or page numbers
##' @importFrom zoo na.approx

seq.citation <- function(x) {

## Result if lenght of the integer vector is 1. 
if(length(x) == 1) return(x) else {

## Sort
x <- sort(x)

## Difference
df <- diff(x)

## Index to determine start and end points
ind <- c("start", rep("no", length(df)-1), "end")
ind[which(df > 1)] <- "end"

## Temporary start point vector
sts <- which(ind == "end") + 1
ind[sts[sts < length(ind)]] <- "start"

## Replace the first index element
ind[1] <- "start"

## Replace the last index element, if preceding one is "end"
if(ind[length(ind)-1] == "end") ind[length(ind)] <- "start"

## Groups for comma separation using "start" as the determining value.
grp <- rep(NA, length(x))
grp[which(ind == "start")] <- 1:length(grp[which(ind == "start")])
grp <- zoo::na.approx(grp, method = "constant", rule = 2)

## Split sequences by group
seqs <- split(x, grp)

seqs <- lapply(seqs, function(k) {
  if(length(k) == 1) k else {
    if(length(k) == 2) paste(k[1], k[2], sep = ",") else {
  paste(k[1], k[length(k)], sep = "-")
  }}
})

## Result
return(do.call("paste", c(seqs, sep = ",")))
}
}

seq.citation(x)
# [1] "1-3,5,6,8-11,13"
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-08-09 11:48:35

您可以很容易地通过基数R使用tapply

代码语言:javascript
运行
复制
paste(tapply(x, cumsum(c(1, diff(x) != 1)), function(i) 
    ifelse(length(i) > 2, paste0(head(i, 1), '-', tail(i, 1)), 
                            paste(i, collapse = ','))), collapse = ',')

[1] "1-3,5,6,8-11,13"
票数 8
EN

Stack Overflow用户

发布于 2017-08-09 11:48:47

这适用于您的示例,并且应该是相当一般的。

代码语言:javascript
运行
复制
# get run lengths of differences, with max value of 2
r <- rle(c(1, pmin(diff(x), 2)))

# paste selected x values with appropriate separator
res <- paste0(x[c(1, cumsum(r$lengths))], c("-", ",")[r$values], collapse="")

# drop final character, which is a separator
res <- substr(res, 1, nchar(res)-1)

这会返回

代码语言:javascript
运行
复制
res
[1] "1-3,5-6,8-11,13"
票数 7
EN

Stack Overflow用户

发布于 2017-08-09 16:48:30

当然,还有来自“seqToHumanReadable”包的R.utils函数。

代码语言:javascript
运行
复制
library(R.utils)
seqToHumanReadable(x)
# [1] "1-3, 5, 6, 8-11, 13"
seqToHumanReadable(x, tau = 1) ## If you want 5-6 and not 5, 6
# [1] "1-3, 5-6, 8-11, 13"

还可以控制结果的外观:

代码语言:javascript
运行
复制
seqToHumanReadable(x, delimiter = "...", collapse = " | ")
# [1] "1...3 | 5 | 6 | 8...11 | 13"
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45589401

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档