Tell me more ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

This one comes from a real life problem. We solved it, of course, but it keeps feeling like it could have be done better, that it's too lengthy and roundabout solution. However none of my colleagues can think of a more succinct way of writing it. Hence I present it as code-golf.

The goal is to convert a nonnegative integer into a string the same way Excel presents its column headers. Thus:

0 -> A
1 -> B
...
25 -> Z
26 -> AA
27 -> AB
...
51 -> AZ
52 -> BA
...
16,383 -> XFD

It has to work at least up to 16,383, but beyond is acceptable too (no bonus points though). I'm looking forward most to the C# solution, but, as per traditions of code-golf, any real programming language is welcome.

share|improve this question
Are you sure that 16383 should be XFD? What do you get for 676 and 702? – Peter Taylor Nov 24 '11 at 23:29
Well, that's what Excel shows, and I found it on the web that it has 16384 columns. I'll test it tomorrow with our (known to work) code (is late night right now where I live). – Vilx- Nov 24 '11 at 23:56
Also, testing with Excel itself reveals that 676=ZA and 702=AAA. – Vilx- Nov 24 '11 at 23:59
The reason I ask is that I wrote some straightforward base-26 code, got results which fit yours precisely, but broke on 676 and 702. – Peter Taylor Nov 25 '11 at 8:21
Yup. It's not Base-26. That's the problem. ;) – Vilx- Nov 25 '11 at 8:44
show 3 more comments

9 Answers

up vote 4 down vote accepted

Perl, 17 characters

say[A..XFD]->[<>]

The .. operator does the same thing as the magical auto-increment, but without the need for the temporary variable and loop. Unless strict subs is in scope, the barewords A and XFD are interpreted as strings.

(This answer was suggested by an anonymous user as an edit to an existing answer. I felt it deserves to be a separate answer, and have made it one. Since it wouldn't be fair for me to gain rep from it, I've made it Community Wiki.)

share|improve this answer
Since it's the shortest answer so far, I guess it deserves to be marked as "accepted" until a shorter solution is found (probably only available in JonSkeetScript) :P Ironic. – Vilx- Sep 24 '12 at 7:55
Since the question is vague on how input and output are done, that actually allows shortening this considerably. For example, if input is in $_ and the output is the value of the expression, then (A..XFD)[$_] solves the challenge with only 12 chars. – Ilmari Karonen Sep 24 '12 at 13:46

Excel Formula:), 36 chars

=SUBSTITUTE(ADDRESS(1,A1,4),"1","")

Usage:

enter image description here

Sorry, couldn't resist ...

share|improve this answer
Arghh! I had actually thought of prohibiting this, but forgot to mention it in the post! :D Still, Excel formulas are not a programming language (and yes, Excel VBA is off limits too). :P – Vilx- Nov 25 '11 at 8:42
@Vilx- Thanks God someone came up with a shorter solution. I don't want to enter history being the only person who won a golf contest using Excel formulas :) – belisarius Nov 26 '11 at 1:30
I still might accept your answer. >:D – Vilx- Nov 26 '11 at 13:30
@Vilx- That would be slightly sadistic on your part :) – belisarius Nov 26 '11 at 13:36
1  
<laughter type="evil">Muhahahahaha!</laughter> – Vilx- Nov 26 '11 at 22:31

Perl, 26 characters

$x='A';map$x++,1..<>;say$x
share|improve this answer

Haskell, 48

f=(!!)(sequence=<<(tail$iterate(['A'..'Z']:)[]))

Less golfed:

f n = (concatMap sequence $ tail $ iterate (['A'..'Z'] :) []) !! n

Explanation

Haskell's sequence combinator takes a list of actions and performs them, returning the result of each action in a list. For example:

sequence [getChar, getChar, getChar]

is equivalent to:

do
    a <- getChar
    b <- getChar
    c <- getChar
    return [a,b,c]

In Haskell, actions are treated like values, and are glued together using the >>= (bind) and return primitives. Any type can be an "action" if it implements these operators by having a Monad instance.

Incidentally, the list type has a monad instance. For example:

do
    a <- [1,2,3]
    b <- [4,5,6]
    return (a,b)

This equals [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)] . Notice how the list comprehension is strikingly similar:

[(a,b) | a <- [1,2,3], b <- [4,5,6]]

Because lists are a type of "action", we can use sequence with lists. The above can be expressed as:

sequence [[1,2,3],[4,5,6]]

Thus, sequence gives us combinations for free!

Thus, to build the list:

["A","B"..."Z","AA","AB"]

I just need to build lists to pass to sequence

[['A'..'Z'],['A'..'Z','A'..'Z'],...]

Then use concatMap to both apply sequence to the lists, and concatenate the resulting lists. Coincidentally, concatMap is the =<< function for lists, so the list monad lets me shave a few characters here, too.

share|improve this answer

C, 53 characters

It's like playing golf with a hammer...

char b[4],*p=b+3;f(i){i<0||(*--p=i%26+65,f(i/26-1));}

Normal version:

char b[4];
char *p = b+3;
void f(int i) {
    if (i >= 0) {
        --p;
        *p = i%26 + 65;
        f(i/26-1);
    }
}

And the usage is like that:

int main(int argc, char *argv[])
{
    f(atoi(argv[1]));
    printf("%s\n", p);
    return 0;
}
share|improve this answer
+1 for "it's like playing golf with a hammer" – Kazark Sep 29 '12 at 15:15

Ruby, 35 characters

e=->n{a=?A;n.times{a.next!};a}

Usage:

puts e[16383]   # XFD

Note: There is also a shorter version (30 characters) using recursion.

    e=->n{n<1??A:e[n-1].next}

But using this function you might have to increase the stack size for large numbers depending on your ruby interpreter.

share|improve this answer

Scala, 62 characters

def f(i:Int):String=if(i<0)""else f((i/26)-1)+(i%26+65).toChar

Usage:

println(f(16383))

returns:

XFD

You can try this on Simply scala. Copy and paste the function and use f(some integer) to see the result.

share|improve this answer
You don't need the ""+ on the else case. – Peter Taylor Nov 25 '11 at 11:26
@PeterTaylor Thanks. – Gareth Nov 25 '11 at 12:44

Python 45 51

f=lambda i:i>=0and f(i/26-1)+chr(65+i%26)or''
share|improve this answer
you can remove 2 parentheses by pulling +chr(65+i%26) inside and testing for i>=0, saving you 1 character :) – quasimodo Sep 23 '12 at 15:02
You could also shave 4 characters off by using f=lambda i: rather than def f(i):return – Strigoides Sep 25 '12 at 3:39

Groovy, 47

m={it<0?'':m(((int)it/26)-1)+('A'..'Z')[it%26]}

[0:'A',1:'B',25:'Z',
        26:'AA',
        27:'AB',
        51:'AZ',
        52:'BA',
        16383:'XFD'].collect {k,v-> assert v == m(k);m(k) }
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.