R中的数字转字母功能

3
我已经写了一个函数,可以将数字从1到702转换成字母,具体如下所示:
  • 1 -> A,
  • 2 -> B,
  • 27 -> AA,
  • 29 -> AC,
  • 以此类推。
我们将这个函数用于报告附录的“编号”/“字母化”。我想让它更加通用,能够处理任何大小的正整数。如果我可以轻松地将原始数字转换为26进制,那么这将更容易,但我在R中没有看到简单的方法。
appendix_lettering <- function(number) {
  if (number %in% 1:26) {
    return(LETTERS[[number]])
  } else if (number %in% 27:702) {
    first_digit <- (floor((number - 1) / 26))
    second_digit <- ((number - 1) %% 26) + 1
    first_letter <- LETTERS[[first_digit]]
    second_letter <- LETTERS[[second_digit]]
    return(paste0(first_letter, second_letter))
  }
}

有没有建议如何最轻松地改进此函数以处理任何正整数(或至少更多)的人?


重复问题的被接受答案是有限制的,但其他答案适用于任何正整数。 - Gregor Thomas
4个回答

6

以下是一些替代方案:

1) 编码 让 b 成为进制基数,这里 b = 26。那么有 b^k 种附录,每个附录都有 k 个字母, 所以对于特定编号为 x 的附录,如果存在最小的整数 n 满足 b + b^2 + ... + b^n >= x, 则该附录包含 n 个字母。此不等式的左侧为一个等比数列,因此有一个闭合形式的解。 将左侧替换为该表达式并解决所得到的方程以获得 code 下方的 n 公式。然后,从所有满足 k < n 的数字中减去所有 b^k 项,并使用 APL-like encode 函数(在 此处 和网络上的其他地方找到)。encode 进行基数转换,给出一个基数为 base 中的数字向量 digits。 最后,将每个数字加 1 并将其用作查找到 LETTERS 中。

app2 <- function(number, base = 26) {
    n <- ceiling(log((1/(1 - base) - 1 - number) * (1 - base), base = base)) - 1
    digits <- encode(number - sum(base^seq(0, n-1)), rep(base, n))
    paste(LETTERS[digits + 1], collapse = "")
}

sapply(1:29, app2) # test

提供:

[1] "A"  "B"  "C"  "D"  "E"  "F"  "G"  "H"  "I"  "J"  "K"  "L"  "M"  "N"  "O" 
[16] "P"  "Q"  "R"  "S"  "T"  "U"  "V"  "W"  "X"  "Y"  "Z"  "AA" "AB" "AC"

另一个要尝试的测试是:

sapply(1:60, app2, base = 3)

2) 递归解法 这是一种递归解法。它计算附录编号的最后一个字母,然后将其删除并递归计算其左侧的部分。

app2r <- function(number, base = 26, suffix = "") {
   number1 <- number - 1
   last_digit <- number1 %% base
   rest <- number1 %/% base
   suffix <- paste0(LETTERS[last_digit + 1], suffix)
   if (rest > 0) Recall(rest, base, suffix) else suffix
}

# tests
identical(sapply(1:29, app2r), sapply(1:29, app2))
## [1] TRUE
identical(sapply(1:60, app2r, base = 3), sapply(1:60, app2, base = 3))
## [1] TRUE

哇,这些很棒。我觉得你的递归解决方案非常巧妙、干净,最重要的是易于阅读。谢谢。 - ctesta01
这些是很好的答案!您是否考虑将它们添加到(新标记的)重复问题中? - Gregor Thomas
我已经在那个问题下添加了一条评论,指向这里。 - G. Grothendieck

0

这种方法非常有效,尽管它与您的原始函数几乎没有关系。它并不完美,但可以轻松地推广到任意数量的字母。此版本可以处理任何数字,最多可达26+26^2+26^3+26^4+26^5+26^6 = 321272406,即最多6个字母。

首先,我们定义一个确定字母数量并调整数字以删除具有较少字母组合的函数。

例如,考虑数字702。它是字母“ZZ”,但只有26^2 = 676种可能的两个字母组合 - 因此,我们必须在“调整后的数字”中先减去26个单个字母。现在,如果调整后的数字为1,而我们有5个字母,则结果单词为“AAAAA”,如果为2,则为“AAAAB”,依此类推。

以下是这些函数:

checknum <- function(num) {
  adnum<-num; #adjusted number
  n_lett<-1; #number of letters
  if(log(adnum,base=26) > 1) {adnum<-adnum-26; n_lett<-2}
  if(log(adnum,base=26) > 2) {adnum<-adnum-26^2; n_lett<-3}
  if(log(adnum,base=26) > 3) {adnum<-adnum-26^3; n_lett<-4}
  if(log(adnum,base=26) > 4) {adnum<-adnum-26^4; n_lett<-5}
  if(log(adnum,base=26) > 5) {adnum<-adnum-26^5; n_lett<-6}
  return(list(adnum=adnum,n_lett=n_lett))
} #this function can be adjusted for more letters or maybe improved in its form

applett2 <- function(num) {
  n_lett<-checknum(num)$n_lett;
  adnum<-checknum(num)$adnum-1;
  out<-c(rep(1,n_lett));
  for(i in 1:n_lett) {
    out[i]<-(floor(adnum/(26^(n_lett-i)))%%26)+1;
  }
  return(paste(LETTERS[out],collapse=""))
} #main function that creates the letters

applett2(26+26^2+26^3+26^4)
# "ZZZZ"
applett2(1234567)
# "BRFGI"

0

可以使用R中的取模运算符(%%)和除法编写一个短函数进行转换。由于R是1索引,这使得它稍微棘手一些,因为表示实际上不是基础,因为0不存在,如果我们有A = 0,那么我们将有BA=26而没有AAAB等。

以下函数解决了这个问题,并匹配您的定义。

base26_conversion <- function(number){
  result <- "";
  base <- 26
  number <- number - 1
  repeat{
    result <- paste0(LETTERS[(number) %% base + 1], result)
    number <- floor(number / base) - 1
    if (!(number > -1)){
      break
    }
  }
  return(result)
}

取模运算符将提取当前的“数字”,加1将纠正索引以获取相应的字母。除法将在26进制中将小数点移动一位。减去1确保排除“0”。

该函数为您的函数的整个输入范围提供匹配字符串,并且应推广到任何正数。


0
这是一个可能的解决方案:
dec2abc<- function(number){
    digit<- LETTERS[(number-1)%%26+1]
    number<- (number - 1 - (number-1)%%26)/26
    while (number > 26){
        digit<- paste0(LETTERS[(number-1)%%26+1], digit)
        number<- (number - 1 - (number-1)%%26)/26 
        }
    digit<- paste0(LETTERS[number], digit)
    return(digit)
}

这适用于任何正整数,但我认为你添加的数字越多,就会测试计算机的内存能力。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接