This question already has an answer here:
I have written a function which works on the integers from 1 to 702 for converting a number to a letter in a very specific way. Here are some examples of how I would like the lettering function to work:
- 1 -> A,
- 2 -> B,
- 27 -> AA,
- 29 -> AC,
- and so on.
We use this function for "numbering" / "lettering" our appendices in reports. I'm looking to make it more general, such that it can handle positive integers of any size. If I could easily convert the original number to base 26, this would be easier, but I do not see an easy way to do that in 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))
}
}
Does anyone have suggestions for how I can most easily improve this function to handle any positive integers (or at least many more)?
Here are some alternatives:
1) encode Let b be the base. Here b = 26. Then there are b^k appendices having k letters so for a particular appendix having number x it has n letters if n is the smallest integer for which b + b^2 + ... + b^n >= x. The LHS of this inequality is a geometric series and therefore has a closed form solution. Replacing the LHS with that expression and solving the resulting equation for n gives the formula for n in the code below. Then we subtract all b^k terms from number for which k < n and use the APL-like
encode
function found here (and elsewhere on the web).encode
does the base conversion givingdigits
, a vector of digits in basebase
. Finally add 1 to each digit and use that as a lookup intoLETTERS
.giving:
Another test to try is:
2) recursive solution Here is an alternative that works recursively. It computes the last letter of the Appendix number and then removes it and recursively computes the portion to its left.
It is possible to write a short function to do the conversion in R using the modulo operator (
%%
) and division. That R is 1-indexed makes it a bit trickier as well as fact that the representation is not really a basis since 0 does not exist, and if we hadA = 0
instead we would haveBA=26
and noAA
,AB
etc.The following function solves this and matches your definition.
The modulo operator will extract the current "digit" and the addition of 1 will correct the index to get the corresponding letter. The division will shift the decimal point by one digit in the 26-base. The subtraction of 1 makes sure that to exclude "0".
The function gives matching strings for the entire input range of your function and should generalize to any positive number.
This approach works nicely, even though it has little to do with your original function. It is not perfect, but can be generalized to any amount of letters easily. This version can handle any number up to
26+26^2+26^3+26^4+26^5+26^6 = 321272406
, i.e. up to 6 letters.First, we define a function that determines the number of letters and adjusts the number, to remove the combinations with a lower number of letters.
Consider for example the number
702
. It is "ZZ" in letters, but there are only26^2 = 676
possible combinations with two letters - hence, we have to subtract the26
single letters beforehand for the "adjusted number". Now, if the adjusted number is, e.g. 1 and we have 5 letters, the resulting word is "AAAAA", for 2 it is "AAAAB" and so on.Here are the functions:
Here's a possible solution:
This works with any positive integer, but I think the more digits you add to the number, you'll be testing the memory abilities of your computer.