Traverse the alphabet from a to z using C#
P粉982881583
P粉982881583 2023-08-23 09:51:55
0
2
497
<p>I have a question about traversing the alphabet. I want a loop that starts at "a" and ends at "z". Then, the loop starts from "aa" and counts up to "az". Then start from "ba", go to "bz", and so on...</p> <p>Does anyone know a solution? </p> <h2>Thank you</h2> <p>Edit: I forgot, I give a character "a" to the function and then the function must return "b". If "bnc" is given, the function must return "bnd". </p>
P粉982881583
P粉982881583

reply all(2)
P粉764836448

First try, just use a-z then aa-zz

public static IEnumerable<string> GetExcelColumns()
{
    for (char c = 'a'; c <= 'z'; c++)
    {
        yield return c.ToString();
    }
    char[] chars = new char[2];
    for (char high = 'a'; high <= 'z'; high++)
    {
        chars[0] = high;
        for (char low = 'a'; low <= 'z'; low++)
        {
            chars[1] = low;
            yield return new string(chars);
        }
    }
}

Note that this will stop at 'zz'. Of course, there are some ugly repetitions in the loop. Fortunately, this is easy to fix - and it can also be more flexible:

Second attempt: a more flexible alphabet

private const string Alphabet = "abcdefghijklmnopqrstuvwxyz";

public static IEnumerable<string> GetExcelColumns()
{
    return GetExcelColumns(Alphabet);
}

public static IEnumerable<string> GetExcelColumns(string alphabet)
{
    foreach(char c in alphabet)
    {
        yield return c.ToString();
    }
    char[] chars = new char[2];
    foreach(char high in alphabet)
    {
        chars[0] = high;
        foreach(char low in alphabet)
        {
            chars[1] = low;
            yield return new string(chars);
        }
    }
}

Now, if you only want to generate a, b, c, d, aa, ab, ac, ad, ba, etc., you can call GetExcelColumns("abcd").

Third Attempt (Further Revised) - Infinite Sequence

public static IEnumerable<string> GetExcelColumns(string alphabet)
{
    int length = 0;
    char[] chars = null;
    int[] indexes = null;
    while (true)
    {
        int position = length-1;
        // 尝试递增最低有效值。
        while (position >= 0)
        {
            indexes[position]++;
            if (indexes[position] == alphabet.Length)
            {
                for (int i=position; i < length; i++)
                {
                    indexes[i] = 0;
                    chars[i] = alphabet[0];
                }
                position--;
            }
            else
            {
                chars[position] = alphabet[indexes[position]];
                break;
            }
        }
        // 如果我们到达数组的开始位置,我们需要一个额外的值
        if (position == -1)
        {
            length++; 
            chars = new char[length];
            indexes = new int[length];
            for (int i=0; i < length; i++)
            {
                chars[i] = alphabet[0];
            }
        }
        yield return new string(chars);
    }
}

Maybe using recursion will lead to clearer code, but the efficiency will not be that high.

Please note that if you want to stop at a specific point, you can use LINQ:

var query = GetExcelColumns().TakeWhile(x => x != "zzz");

"Restart" iterator

To restart the iterator from a given point, you can use SkipWhile as thesoftwarejedi suggested. Of course, this is quite inefficient. If you can maintain any state between calls, you can retain the iterator (for either solution):

using (IEnumerator<string> iterator = GetExcelColumns())
{
    iterator.MoveNext();
    string firstAttempt = iterator.Current;

    if (someCondition)
    {
        iterator.MoveNext();
        string secondAttempt = iterator.Current;
        // etc
    }
}

Alternatively, you might be able to structure your code to use foreach, breaking when the first value is found that can actually be used.

P粉920485285

Edit: Make it exactly as per the latest edits to the original post

This is the simplest solution and tested:

static void Main(string[] args)
{
    Console.WriteLine(GetNextBase26("a"));
    Console.WriteLine(GetNextBase26("bnc"));
}

private static string GetNextBase26(string a)
{
    return Base26Sequence().SkipWhile(x => x != a).Skip(1).First();
}

private static IEnumerable<string> Base26Sequence()
{
    long i = 0L;
    while (true)
        yield return Base26Encode(i++);
}

private static char[] base26Chars = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
private static string Base26Encode(Int64 value)
{
    string returnValue = null;
    do
    {
        returnValue = base26Chars[value % 26] + returnValue;
        value /= 26;
    } while (value-- != 0);
    return returnValue;
}
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template