tags:

views:

537

answers:

7

I am trying to create a function which will give me alphabet position when an index is passed. It will be same like how excel shows it's columns. A...Z, AA,AB.... I wrote the below function to get the results upto Z. It looks like

static string GetColumnName(int index)
{
    const int alphabetsCount = 26;
    if (index <= alphabetsCount)
    {
        int code = (index - 1) + (int)'A';
        return char.ConvertFromUtf32(code);
    }
    return string.Empty;
}

This works fine until 'Z'. It return 'A' if I pass 1 and return 'B' if I pass 2 and so on. But, I am not able to figure out how will I get AA when I pass 27 to this function. I guess I need a recursive method to find it.

Any inputs to this problem will be great!

Edit

This is suggested by Tordek. But his code will fail in numbers like 52, 78 etc. Added workaround for that and here is the final working code.

static string GetColumnName(int index)
{
    const int alphabetsCount = 26;

    if (index > alphabetsCount)
    {
        int mod = index % alphabetsCount;
        int columnIndex = index / alphabetsCount;

        // if mod is 0 (clearly divisible) we reached end of one combination. Something like AZ
        if (mod == 0)
        {
            // reducing column index as index / alphabetsCount will give the next value and we will miss one column.
            columnIndex -= 1;
            // passing 0 to the function will return character '@' which is invalid
            // mod should be the alphabets count. So it takes the last char in the alphabet.
            mod = alphabetsCount;
        }
        return GetColumnName(columnIndex) + GetColumnName(mod);
    }
    else
    {
        int code = (index - 1) + (int)'A';
        return char.ConvertFromUtf32(code);
    }
}
A: 

Recursion is one possibility -- if index > 26, you deal with index % 26 in this call and concatenate it to a recursive call on index / 26. However, iteration is often speedier and not hard to arrange for simple cases such as this one. In pseudocode:

string result = <convert `index % 26`>
while index > 26:
  index = index / 26
  result = <convert `index % 26`> + result
return result

or the like.

Alex Martelli
There's nothing wrong with your pseudocode, but it's important to know that you should probably use the StringBuilder class if you're going to be appending to a string in a loop, to save on object allocations: http://msdn.microsoft.com/en-us/library/system.text.stringbuilder(loband).aspx
Paul Fisher
This is wrong because it is not a base 26 system. If A would be 0, A would equal AA (0 == 00). If A would be 1, going from Z to AA would be like going from 9 to 11.
Daniel Brückner
Paul, StringBuilder is overkill. A 32-bit int is 2^32 and 26^7 overflows it so the max is 7 letters long. 7 iterations is hardly taxing. A 64-bit long would only have 14 letters. :)
Colin Burnett
A: 
static string GetColumnName(int index)
{
    const int alphabetsCount = 26;
    string result = '';

    if (index >= alphabetsCount)
    {
        result += GetColumnName(index-alphabetsCount)
    }
    return (string) (64 + index);
}

My C# is HORRIBLE AND RUSTY. Interpret this as pseudocode - it will almost certainly not compile, but may get you started.

Anonymous Cow
+4  A: 

See this question:
http://stackoverflow.com/questions/297213/translate-an-index-into-an-excel-column-name

or this one:
http://stackoverflow.com/questions/181596/how-to-convert-a-column-number-eg-127-into-an-excel-column-eg-aa#182924

Though the first link has a correct answer right at the top and the 2nd has several that are not correct.

Joel Coehoorn
+3  A: 

Any recursive function can be converted into an equivalent iterative one. I find it always easy to think recursively first:

static string GetColumnName(int index)
{
    const int alphabetsCount = 26;

    if (index > alphabetsCount) {
        return GetColumnName(index / alphabetsCount) + GetColumnName(index % alphabetsCount);
    } else {
        int code = (index - 1) + (int)'A';
        return char.ConvertFromUtf32(code);
    }
}

Which can be simple converted into:

static string GetColumnName(int index)
{
    const int alphabetsCount = 26;
    string result = string.Empty;

    while (index > 0) {
        result = char.ConvertFromUtf32(64 + (index % alphabetsCount)) + result;
        index /= alphabetsCount;
    }

    return result;
}

Even so, listen to Joel.

Tordek
Great. My math is rusty. So couldn't figure out modulo operation. Thanks for the code.
Appu
A: 

If you are going to be using this type of lookup many times, a good optimization is to store your alphabet for later use, you can do this with your algorithm of choice.

I like the following because it is immediately apparent to anyone that looks at it what it does.

public static string[] letters
    {
        get
        {
            return new string[]{"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",
                "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK","AL","AM",
                "AN","AO","AP","AQ","AR","AS","AT","AU","AV","AW","AX","AY","AZ",
                "BA","BB","BC","BD","BE","BF","BG","BH","BI","BJ","BK","BL","BM",
                "BN","BO","BP","BQ","BR","BS","BT","BU","BV","BW","BX","BY","BZ",
                "CA","CB","CC","CD","CE","CF","CG","CH","CI","CJ","CK","CL","CM",
                "CN","CO","CP","CQ","CR","CS","CT","CU","CV","CW","CX","CY","CZ",
                "DA","DB","DC","DD","DE","DF","DG","DH","DI","DJ","DK","DL","DM",
                "DN","DO","DP","DQ","DR","DS","DT","DU","DV","DW","DX","DY","DZ",
                "EA","EB","EC","ED","EE","EF","EG","EH","EI","EJ","EK","EL","EM",
                "EN","EO","EP","EQ","ER","ES","ET","EU","EV","EW","EX","EY","EZ",
                "FA","FB","FC","FD","FE","FF","FG","FH","FI","FJ","FK","FL","FM",
                "FN","FO","FP","FQ","FR","FS","FT","FU","FV","FW","FX","FY","FZ",
                "GA","GB","GC","GD","GE","GF","GG","GH","GI","GJ","GK","GL","GM",
                "GN","GO","GP","GQ","GR","GS","GT","GU","GV","GW","GX","GY","GZ",
                "HA","HB","HC","HD","HE","HF","HG","HH","HI","HJ","HK","HL","HM",
                "HN","HO","HP","HQ","HR","HS","HT","HU","HV","HW","HX","HY","HZ",
                "IA","IB","IC","ID","IE","IF","IG","IH","II","IJ","IK","IL","IM",
                "IN","IO","IP","IQ","IR","IS","IT","IU","IV"};
        }
    }

If you need more columns put the following formula in Excel fill right as far as needed: =LEFT(ADDRESS(1,COLUMN(A1),4),LEN(ADDRESS(1,COLUMN(A1),4)) - 1)

pflunk
A: 

You almost have it already.

Instead of using index to calculate the code, use (index % alphabetsCount) and then divide index by alphabetsCount.

Keep looping on that code while index is not zero. Each iteration of the loop will get you one character of the name.

Shmoopty
A: 

I don't want to answer the question in C# but I'm going to show you how easy this is in Haskell.

alphas :: [String]
alphas = [x ++ [c] | x <- ([]:alphas), c <- ['A'..'Z']]

Prelude> take 100 alphas
["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","AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK",
 "AL","AM","AN","AO","AP","AQ","AR","AS","AT","AU","AV","AW","AX","AY","AZ","BA",
 "BB","BC","BD","BE","BF","BG","BH","BI","BJ","BK","BL","BM","BN","BO","BP","BQ",
 "BR","BS","BT","BU","BV","BW","BX","BY","BZ","CA","CB","CC","CD","CE","CF","CG",
 "CH","CI","CJ","CK","CL","CM","CN","CO","CP","CQ","CR","CS","CT","CU","CV"]
Dietrich Epp