r - 由连字符组成的数字序列,而不用连字符连接单个出现的数字

标签 r sequence

我想生成可读的数字序列(例如 1, 2, 3, 4 = 1-4),但对于一组数据,序列中的每个数字都必须有四位数字(例如99 = 00991 = 00011022 = 1022)并且每个数字前面有不同的字母。

我正在查看answer对此question ,它几乎完全按照我想要的方式进行,但有两个警告:

  1. 如果有一个独立的数字没有出现在序列中,它将出现两次,中间有连字符
  2. 如果有多个独立数字未出现在序列中,则它们不会包含在结果中
### Create Data Set ====
## Create the data for different tags. I'm only using two unique levels here, but in my dataset I've got
## 400+ unique levels.
FM <- paste0('FM', c('0001', '0016', '0017', '0018', '0019', '0021', '0024', '0026', '0028'))
SC <- paste0('SC', c('0002', '0003', '0004', '0010', '0012', '0014', '0033', '0036', '0039'))

## Combine data
my.seq1 <- c(FM, SC)

## Sort data by number in sequence
my.seq1 <- my.seq1[order(substr(my.seq1, 3, 7))]

### Attempt Number Sequencing ====
## Get the letters
sp.tags <- substr(my.seq1, 1, 2)

## Get the readable number sequence
lapply(split(my.seq1, sp.tags), ## Split data by the tag ID
       function(x){
  
  ## Get the run lengths as per [previous answer][1]
  rl <- rle(c(1, pmin(diff(as.numeric(substr(x, 3, 7))), 2)))
  
  ## Generate number sequence by separator as per [previous answer][1]
  seq2 <- paste0(x[c(1, cumsum(rl$lengths))], c("-", ",")[rl$values], collapse="")
  
  return(substr(seq2, 1, nchar(seq2)-1))
})

## Combine lists and sort elements
my.seq2 <- unlist(strsplit(do.call(c, my.seq2), ","))
my.seq2 <- my.seq2[order(substr(my.seq2, 3, 7))]
names(my.seq2) <- NULL

my.seq2
[1] "FM0001-FM0001" "SC0002-SC0004" "FM0016-FM0019" "FM0028" "SC0039"

my.seq1
[1] "FM0001" "SC0002" "SC0003" "SC0004" "SC0010" "SC0012" "SC0014" "FM0016" "FM0017" "FM0018" "FM0019" "FM0021"
[13] "FM0024" "FM0026" "FM0028" "SC0033" "SC0036" "SC0039"

主要问题是:

  1. 数据集中完全缺少某些值(例如 FM0021FM0024FM0026)
  2. 序列中的第一个数字 (FM0001) 显示,中间有一个连字符

使用 A5C1D2H2I1M1N2O1R2T1 我感觉自己变得更温暖了的answer使用 seqToHumanReadable 因为它非常优雅并且解决了这两个问题。还有两个问题是,我无法在每个数字之前标记 ID,也无法强制将位数变为四(例如 0004 变为 4)。

library(R.utils)

lapply(split(my.seq1, sp.tags), function(x){
  return(unlist(strsplit(seqToHumanReadable(substr(x, 3, 7)), ',')))
})

$FM
[1] "1"      " 16-19" " 21"    " 24"    " 26"    " 28"   

$SC
[1] "2-4" " 10" " 12" " 14" " 33" " 36" " 39"

理想的结果是:

"FM0001, SC002-SC004, SC0012, SC0014, FM0017-FM0019, FM0021, FM0024, FM0026, FM0028, SC0033, SC0036, SC0039"

有什么想法吗?这是手动完成的非常简单的事情之一,但需要花费眨眼的时间,并且您认为应该存在一个函数,但我还没有找到它,或者它不存在 :(

最佳答案

这应该可以吗?

# get the prefix/tag and number
tag <- gsub("(^[A-z]+)(.+)", "\\1", my.seq1)
num <- gsub("([A-z]+)(\\d+$)", "\\2", my.seq1)

# get a sequence id
n <- length(tag)
do_match <- c(FALSE, diff(as.numeric(num)) == 1 & tag[-1] == tag[-n])
seq_id <- cumsum(!do_match) # a sequence id

# tapply to combine the result
res <- setNames(tapply(my.seq1, seq_id, function(x)
  if(length(x) < 2)
    return(x)
  else
    paste(x[1], x[length(x)], sep = "-")), NULL)

# show the result
res
#R>  [1] "FM0001"        "SC0002-SC0004" "SC0010"        "SC0012"        "SC0014"        "FM0016-FM0019" "FM0021"       
#R>  [8] "FM0024"        "FM0026"        "FM0028"        "SC0033"        "SC0036"        "SC0039"

# compare with 
my.seq1
#R>  [1] "FM0001" "SC0002" "SC0003" "SC0004" "SC0010" "SC0012" "SC0014" "FM0016" "FM0017" "FM0018" "FM0019" "FM0021" "FM0024"
#R> [14] "FM0026" "FM0028" "SC0033" "SC0036" "SC0039"

数据

FM <- paste0('FM', c('0001', '0016', '0017', '0018', '0019', '0021', '0024', '0026', '0028'))
SC <- paste0('SC', c('0002', '0003', '0004', '0010', '0012', '0014', '0033', '0036', '0039'))
my.seq1 <- c(FM, SC)
my.seq1 <- my.seq1[order(substr(my.seq1, 3, 7))]

关于r - 由连字符组成的数字序列,而不用连字符连接单个出现的数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64329590/

相关文章:

c - C 语言冰雹序列

java - 将弯音发送到 Java 中的 MIDI 音序器

r - 将数据框拆分为重叠的数据框

java - 将 Python 编写的方法转换为 Java

python - tensorflow 预测序列

r - 动态连接多个表

sql-server - SQL Server 如何确定序列中的下一个值?

r - 使用带有插入符号训练的神经网络并调整参数

r - 将图像插入图表区域外的 ggplot

r - 使用 ifelse 从 R 中的数据集中删除不需要的行