第一次嘗試,只使用a-z然後是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); } } }
請注意,這將在'zz'處停止。當然,循環中存在一些醜陋的重複。幸運的是,這很容易解決 - 並且它還可以更加靈活:
第二次嘗試:更靈活的字母
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); } } }
現在,如果你只想產生a、b、c、d、aa、ab、ac、ad、ba等,你可以呼叫GetExcelColumns("abcd")。
GetExcelColumns("abcd")
第三次嘗試(進一步修訂)- 無限序列
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); } }
可能使用遞迴會有更清晰的程式碼,但效率不會那麼高。
請注意,如果你想在某個特定點停止,你可以使用LINQ:
var query = GetExcelColumns().TakeWhile(x => x != "zzz");
「重新啟動」迭代器
要從給定點重新啟動迭代器,你可以像thesoftwarejedi建議的那樣使用SkipWhile。當然,這相當低效。如果你能在呼叫之間保持任何狀態,你可以保留迭代器(對於任一解決方案):
SkipWhile
using (IEnumerator<string> iterator = GetExcelColumns()) { iterator.MoveNext(); string firstAttempt = iterator.Current; if (someCondition) { iterator.MoveNext(); string secondAttempt = iterator.Current; // etc } }
或者,你可能能夠建立你的程式碼以使用foreach,在找到第一個可以實際使用的值時中斷。
foreach
編輯:使其完全按照原始帖子的最新編輯要求執行
這是最簡單的解決方案,並經過測試:
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; }
第一次嘗試,只使用a-z然後是aa-zz
請注意,這將在'zz'處停止。當然,循環中存在一些醜陋的重複。幸運的是,這很容易解決 - 並且它還可以更加靈活:
第二次嘗試:更靈活的字母
現在,如果你只想產生a、b、c、d、aa、ab、ac、ad、ba等,你可以呼叫
GetExcelColumns("abcd")
。第三次嘗試(進一步修訂)- 無限序列
#可能使用遞迴會有更清晰的程式碼,但效率不會那麼高。
請注意,如果你想在某個特定點停止,你可以使用LINQ:
「重新啟動」迭代器
要從給定點重新啟動迭代器,你可以像thesoftwarejedi建議的那樣使用
SkipWhile
。當然,這相當低效。如果你能在呼叫之間保持任何狀態,你可以保留迭代器(對於任一解決方案):或者,你可能能夠建立你的程式碼以使用
foreach
,在找到第一個可以實際使用的值時中斷。編輯:使其完全按照原始帖子的最新編輯要求執行
#這是最簡單的解決方案,並經過測試: