7

i am looking for code that can generate an array where the first item is A, then B, then C . . .after Z it would then go to AA, then AB then AC . . . all the way up to ZZ.

what is the best way of doing this in C#?

leora
  • 188,729
  • 360
  • 878
  • 1,366

10 Answers10

29

One of the ways is:

IEnumerable<string> generate()
{
    for (char c = 'A'; c <= 'Z'; c++)
        yield return new string(c, 1);
    for (char c = 'A'; c <= 'Z'; c++)
        for (char d = 'A'; d <= 'Z'; d++)
            yield return new string(new[] { c, d });
}

Edit:
you can actually produce "infinite" sequence (bounded by maximal long value) with somewhat more complicated code:

string toBase26(long i)
{
    if (i == 0) return ""; i--;
    return toBase26(i / 26) + (char)('A' + i % 26);
}

IEnumerable<string> generate()
{
    long n = 0;
    while (true) yield return toBase26(++n);
}

This one goes like that: A, B, ..., Z, AA, AB, ..., ZZ, AAA, AAB, ... etc:

foreach (var s in generate().Take(200)) Console.WriteLine(s);
Vlad
  • 35,022
  • 6
  • 77
  • 199
  • 2
    This is so simple and elegant it's scary :) – kprobst Mar 21 '11 at 22:46
  • I would return `new string(new [] {c, d})` in second case – Snowbear Mar 21 '11 at 22:48
  • @Snowbear: yes, your way is more elegant, I'll change it. – Vlad Mar 21 '11 at 22:52
  • 2
    This is not Base 26, because `AA` is not the same as `A`. See also http://stackoverflow.com/questions/763691/programming-riddle-how-might-you-translate-an-excel-column-name-to-a-number where several answers also gave an inverse operation. – Svante Mar 22 '11 at 12:48
  • @Svante: yes, but it's quite close to. The name is slightly misleading, I agree. (The inverse operation is trivial as well.) – Vlad Mar 22 '11 at 12:49
6

Great answer of Vlad.

Here's another variation on that:

 static IEnumerable<string> generate() {
   for (char c = 'A'; c <= 'Z'; c++) {
     yield return c.ToString();
   }

   foreach (string s in generate()) {
     for (char c = 'A'; c <= 'Z'; c++) {
       yield return s + c;
     }
   }
 }

If you don't mind starting the sequence with an empty string you could write it as follows:

 static IEnumerable<string> generate() {
   yield return "";

   foreach (string s in generate()) {
     for (char c = 'A'; c <= 'Z'; c++) {
       yield return s + c;
     }
   }
 }
Jan
  • 8,011
  • 3
  • 38
  • 60
  • 2
    Wow, nice infinite recursion usage! I wish I had invented this. It could be even simpler if replace the first loop with just `yield return "";`. – Vlad Mar 27 '11 at 14:14
1

You could generate numbers using Enumerable.Range and cast them to char to generate A-Z. Next step is to combine them.

Zebi
  • 8,682
  • 1
  • 36
  • 42
1

Found this in SO albeit in PHP. Would this help? Algorithm to get the excel-like column name of a number

Community
  • 1
  • 1
WorldIsRound
  • 1,544
  • 10
  • 15
1
var q = Enumerable.Range(Convert.ToInt32('A'),26).Select( x => Convert.ToChar(x) );
var result = (
  q.Select( x => x.ToString() )
   .Concat( 
      q.SelectMany(
        x => q.Select( y => x.ToString() + y.ToString() )
      )
   )
);
Kilanash
  • 4,479
  • 1
  • 14
  • 11
  • 3
    Linq should be used to make code readable, not to make code Linqish – Snowbear Mar 21 '11 at 22:53
  • 1
    I think it's perfectly fine as a functional expression of what he was asking for. Vlad's is nicer to look at, true, but only because the compiler hides all the cruft it creates to make this work. – Kilanash Mar 21 '11 at 23:03
1
class Program
{
    public static string IntegerToExcelColumn(int col)
    {
        // I've put a 256 upper bound here because Excel 2003 
        // allows only 256 columns. Change it if you're using 
        // Excel 2007 or 2010.
        Debug.Assert(col >= 1 && col <= 256);

        if (col >= 1 && col <= 26)
        {
            return ((char)(((int)'A') + (col - 1))).ToString();
        }

        // I've put a 256 upper bound here because Excel 2003 
        // allows only 256 columns. Change it if you're using 
        // Excel 2007 or 2010.
        if (col > 26 && col <= 256)
        {
            int rem = col % 26;
            int pri = col / 26;
            if (rem == 0)
            {
                rem = 26;
                pri--;
            }
            char[] buffer = new char[2];
            buffer[0] = (char)(((int)'A') + (pri - 1));
            buffer[1] = (char)(((int)'A') + (rem - 1));
            return new string(buffer);
        }

        return "";
    }

    static void Main(string[] args)
    {
        string[] columns= new string[255];
        for (int i = 1; i <= 255; i++)
            columns[i-1] = IntegerToExcelColumn(i);
        foreach(var col in columns)
            Console.WriteLine(col);
    }
}
Young
  • 442
  • 5
  • 14
1

Here's one way. :)

string[] values =
  Enumerable.Range(0, 27 * 26)
  .Select(
    n => new String(
      new[] { (char)('@' + n / 26), (char)('A' + n % 26) },
      n < 26 ? 1 : 0, n < 26 ? 1 : 2
    )
  )
  .ToArray();
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
0

Have a look at an ASCII table and take note of the values of the characters. You should be able to work out a loop to increment the character from A to Z for as many times as you need to replicate the characters. :)

Tony
  • 9,672
  • 3
  • 47
  • 75
0

You can also try this. A to ZZ

public class Program
{
    public static void Main()
    {
        int c=1;
        string cc=AtoZZ(c);
        for(int i=1;i<=702;i++){
        cc=AtoZZ(i);
        Console.WriteLine(cc);
        }
    }

    static string AtoZZ(int chr)
    {
        char c1;
        char c2;
        string alp = "";
        if(chr<=26)
        {
            c1 = (char)(chr + 64);
            alp = c1 + "";
        }        
        else
        {
            int cl1 = chr / 26;
            int cl2 = chr % 26;
            if(cl2==0){
                cl1--;
                cl2=26;
            }
            c1 = (char)(cl1 + 64);
            c2 = (char)(cl2 + 64);
            alp = c1 + "" + c2;
        }
        return alp;
     }
}
0

To complement Vlad's answer, here's the reverse operation of ToBase26(int):

static long ToBase10(string str)
{
   if (string.IsNullOrWhiteSpace(str)) return 0;
   var value = str[0] - 'A' + 1;

   return (long) (value * Math.Pow(26, str.Length - 1) + 
          ToBase10(str.Substring(1, str.Length - 1)));
}
Sylvain Rodrigue
  • 4,751
  • 5
  • 53
  • 67