Iterating through the Alphabet - C# a-caz

后端 未结 10 1057
無奈伤痛
無奈伤痛 2020-11-29 03:03

I have a question about iterate through the Alphabet. I would like to have a loop that begins with \"a\" and ends with \"z\". After that, the loop begins \"aa\" and count to

相关标签:
10条回答
  • 2020-11-29 03:48

    First effort, with just 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's some ugly duplication here in terms of the loops. Fortunately, that's easy to fix - and it can be even more flexible, too:

    Second attempt: 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 want to generate just a, b, c, d, aa, ab, ac, ad, ba, ... you'd call GetExcelColumns("abcd").

    Third attempt (revised further) - infinite sequence

    public static IEnumerable<string> GetExcelColumns(string alphabet)
    {
        int length = 0;
        char[] chars = null;
        int[] indexes = null;
        while (true)
        {
            int position = length-1;
            // Try to increment the least significant
            // value.
            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 we got all the way to the start of the array,
            // we need an extra value
            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);
        }
    }
    

    It's possible that it would be cleaner code using recursion, but it wouldn't be as efficient.

    Note that if you want to stop at a certain point, you can just use LINQ:

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

    "Restarting" the iterator

    To restart the iterator from a given point, you could indeed use SkipWhile as suggested by thesoftwarejedi. That's fairly inefficient, of course. If you're able to keep any state between call, you can just keep 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 may well be able to structure your code to use a foreach anyway, just breaking out on the first value you can actually use.

    0 讨论(0)
  • 2020-11-29 03:49

    just curious , why not just

        private string alphRecursive(int c) {
             var alphabet = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
             if (c >= alphabet.Length) {
                 return alphRecursive(c/alphabet.Length) + alphabet[c%alphabet.Length];
             } else {
                 return "" + alphabet[c%alphabet.Length];
             }
        }
    
    0 讨论(0)
  • 2020-11-29 03:49

    This is like displaying an int, only using base 26 in stead of base 10. Try the following algorithm to find the nth entry of the array

    q = n div 26;
    r = n mod 26;
    s = '';
    while (q > 0 || r > 0) {
      s = alphabet[r] + s;
      q = q div 26;
      r = q mod 26;
    }
    

    Of course, if you want the first n entries, this is not the most efficient solution. In this case, try something like daniel's solution.

    0 讨论(0)
  • 2020-11-29 03:54

    The following populates a list with the required strings:

    List<string> result = new List<string>();
    for (char ch = 'a'; ch <= 'z'; ch++){
        result.Add (ch.ToString());
    }
    
    for (char i = 'a'; i <= 'z'; i++)
    {
        for (char j = 'a'; j <= 'z'; j++)
        {
            result.Add (i.ToString() + j.ToString());
        }
    }
    
    0 讨论(0)
提交回复
热议问题