R中的数字到字母刻字功能

时间:2017-05-30 18:58:00

标签: r converter letters

我编写了一个函数,它可以处理从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))
  }
}

有没有人建议我如何才能最轻松地改进此功能来处理任何正整数(或至少更多)?

4 个答案:

答案 0 :(得分:2)

以下是一些替代方案:

1)编码设b为基数。这里b = 26.然后有b ^ k个附录有k个字母 因此对于具有数字x的特定附录,如果n是,则它具有n个字母 b + b ^ 2 + ... + b ^ n> = x的最小整数。这种不等式的LHS是几何级数,因此具有封闭形式的解决方案。用该表达式替换LHS并求解n的结果等式,得到下面代码中的n的公式。然后我们从数字中减去所有b ^ k项,其中k encode函数找到here(以及网络上的其他地方)。 encode基本转化为digits提供了基数base中的数字向量。最后,为每个数字添加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

答案 1 :(得分: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"

答案 2 :(得分:0)

可以使用模运算符(%%)和除法编写一个短函数来在R中进行转换。 R是1索引使得它有点棘手,以及表示不是真正的基础,因为0不存在,如果我们有A = 0而我们将BA=26而没有{ {1}},AA等。

以下功能解决了这个问题,并与您的定义相符。

AB

模运算符将提取当前“数字”,并且添加1将更正索引以获得相应的字母。除法将在26基数中将小数点移位一位数。减法1确保排除“0”。

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

答案 3 :(得分: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)
}

这适用于任何正整数,但我认为您添加到数字的位数越多,您就会测试计算机的内存容量。