# Generate a Combination of letters by a number

I'm trying to write a function f.

example:

 f /@ Range[0, 52]

(* ==> {A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,

f /@ (10^Range[8])

(* ==> {K,CW,ALM,NTQ,EQXE,BDWGO,UVXWK,HJUNYW} *)


How I do it?

-
Look up FromCharacterCode, that should help you along the way. – jVincent Oct 25 '12 at 9:48
A few ways here stackoverflow.com/questions/4447550/… – Dr. belisarius Oct 25 '12 at 12:08

A version using recursion:

g[n_ /; n < 26] := {n}
g[n_] := {g[Quotient[n, 26] - 1], Mod[n, 26]}
f[n_] := FromCharacterCode[65 + Flatten[g[n]]]

f /@ (10^Range[8])


{"K", "CW", "ALM", "NTQ", "EQXE", "BDWGO", "UVXWK", "HJUNYW"}

-

Three variants of the idea in @Simon's answer using FixedPoint, NestWhile and ReplaceRepeated:

ClearAll[chrctrDgtsF1,chrctrDgtsF2,chrctrDgtsF3];


FixedPoint:

chrctrDgtsF1 =  Function[{n}, FromCharacterCode[65 +
FixedPoint[If[First[#] < 26, #,
Join[QuotientRemainder[First@#, 26] + {-1, 0},  Rest[#]]] &, {n}]]];


NestWhile:

chrctrDgtsF2 = Function[{n}, FromCharacterCode[65 +
NestWhile[Join[QuotientRemainder[First@#, 26] + {-1, 0}, Rest[#]] &, {n},
(First[#] >= 26 &)]]];


ReplaceRepeated:

chrctrDgtsF3 = FromCharacterCode[65 + ({#} //.
{x_, y___} /; x >= 26 :> Flatten@{QuotientRemainder[x, 26] + {-1, 0}, y})] &;


Examples:

chrctrDgtsF1 /@ (10^Range[8])
(* {"K","CW","ALM","NTQ","EQXE","BDWGO","UVXWK","HJUNYW"} *)

(f /@ # == chrctrDgtsF1 /@ # == chrctrDgtsF2 /@ # == chrctrDgtsF3 /@ #) &@
RandomInteger[10^9, {1000}]
(* True *)

-

Edit 1 Thanks to Simon and whuber for pointing out that the original post contained an error. While the approach that I described yields the correct results for the test range, it produces wrong results for other ranges. For example, for Range[670, 680] the results are {"YU", "YV", "YW", "YX", "YY", "YZ", "A@A", "A@B", "A@C", "A@D", "A@E"}, which is clearly not as required.

Edit 2 As whuber points out, the problem with this base is that depending on the circumstances either a 0 or a 1 may correspond with A. For example, when the result of IntegerDigits[n, 26] is {1,0} the string should be AA.

I have adapted the function in such a way that all 0's are done away with, and 1 is set to always mean A. First I increment the input by 1, so the result for 0 becomes {1}, which equals A. Then all 0's which are not at the starting position are replaced by 26 while the preceding number is decremented by one. Then all 0 at the start of the list are simply removed.

This means that the previous result of "A@A" ({1,0,1}) becomes "ZA" ({26, 1}).

 j[n_] := FromCharacterCode[64 + (IntegerDigits[n + 1, 26]
//. {
{s___, p_, 0, r___} -> {s, p - 1, 26, r},
{0, r___} -> {r}
})]


I have validated the results with the method of Simon up to 10^6.

Original post This uses IntegerDigits with base 26 and a correction for the last digit:

FromCharacterCode[64 + (IntegerDigits[#, 26] /. {m___, n_} -> {m, n + 1})] & /@ (10^Range[8])
(* {"K", "CW", "ALM", "NTQ", "EQXE", "BDWGO", "UVXWK", "HJUNYW"} *)

-
Nice code, but it gives A@A instead of ZA for an input value of 676 – Simon Woods Oct 25 '12 at 20:06
This is a great idea, but implementing it is a little trickier than it may look: although this looks like a base 26 code, the correction for the last digit is not what you would expect. The roles of the digits 'a' through 'z' are different in the units place than elsewhere. In the units place, 'a' is a zero, whereas elsewhere, 'a' is a one and the role of zero is played by a blank. This makes it a combination of a base 26 and a base 27 code. – whuber Oct 25 '12 at 20:26