سؤال

لدي سؤال حول التكرار من خلال الأبجدية.أرغب في الحصول على حلقة تبدأ بالحرف "a" وتنتهي بالحرف "z".بعد ذلك، تبدأ الحلقة بـ "aa" ويتم العد إلى "az".بعد ذلك يبدأ بـ "ba" حتى "bz" وهكذا ...

هل يعرف أحدكم بعض الحل؟

شكرًا

يحرر:لقد نسيت أنني أعطيت الحرف "a" للوظيفة ثم يجب أن ترجع الوظيفة b.إذا أعطيت "bnc" فيجب أن ترجع الدالة "bnd"

هل كانت مفيدة؟

المحلول

تحرير: جعله يفعل تماما كما أحدث تحرير وOP ويريد

وهذا هو الحل أبسط، واختبارها:

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;
}

نصائح أخرى

الجهد الأول، فقط باستخدام aa-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").

المحاولة الثالثة (مراجعة إضافية) - تسلسل لا نهائي

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);
    }
}

من الممكن أن يكون هذا كودًا أنظف باستخدام التكرار، لكنه لن يكون بنفس الكفاءة.

لاحظ أنه إذا كنت تريد التوقف عند نقطة معينة، يمكنك فقط استخدام LINQ:

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

"إعادة تشغيل" المكرر

لإعادة تشغيل المكرر من نقطة معينة، يمكنك بالفعل استخدام SkipWhile كما اقترح thesoftwarejedi.وهذا غير فعال إلى حد ما، بطبيعة الحال.إذا كنت قادرًا على الاحتفاظ بأي حالة بين المكالمة، فيمكنك فقط الاحتفاظ بالمكرر (لأي من الحلين):

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

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

وبدلاً من ذلك، قد تتمكن من هيكلة التعليمات البرمجية الخاصة بك لاستخدام ملف foreach على أية حال، ما عليك سوى الخروج من القيمة الأولى التي يمكنك استخدامها فعليًا.

وفيما يلي بملء قائمة مع السلاسل المطلوبة:

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());
    }
}

وأنا أعلم أن هناك الكثير من الإجابات هنا، وانها قبلت واحدة، ولكن IMO أنهم جميعا تجعل من الصعب مما يجب أن يكون. أعتقد أن يلي هو أبسط وأكثر نظافة:

static string NextColumn(string column){
    char[] c = column.ToCharArray();
    for(int i = c.Length - 1; i >= 0; i--){
        if(char.ToUpper(c[i]++) < 'Z')
            break;
        c[i] -= (char)26;
        if(i == 0)
            return "A" + new string(c);
    }
    return new string(c);
}

لاحظ أن هذا لا تفعل أي التحقق من صحة المدخلات. إذا كنت لا تثق المتصلين بك، يجب عليك إضافة الاختيار IsNullOrEmpty في البداية، والاختيار c[i] >= 'A' && c[i] <= 'Z' || c[i] >= 'a' && c[i] <= 'z' في الجزء العلوي من الحلقة. أو مجرد ترك الأمر يكون والسماح لها أن تكون GIGO .

ويمكنك أيضا العثور على استخدام هذه الوظائف رفيق:

static string GetColumnName(int index){
    StringBuilder txt = new StringBuilder();
    txt.Append((char)('A' + index % 26));
    //txt.Append((char)('A' + --index % 26));
    while((index /= 26) > 0)
        txt.Insert(0, (char)('A' + --index % 26));
    return txt.ToString();
}
static int GetColumnIndex(string name){
    int rtn = 0;
    foreach(char c in name)
        rtn = rtn * 26 + (char.ToUpper(c) - '@');
    return rtn - 1;
    //return rtn;
}

ووالصفر المستندة إلى هاتين الوظيفتين. وهذا هو، "A" = 0، "Z" = 25 "AA" = 26، وما إلى ذلك لجعلها المستندة إلى واحد (مثل واجهة COM في Excel)، إزالة خط فوق خط علق في كل وظيفة، وغير تعليق تلك خطوط.

وكما هو الحال مع وظيفة NextColumn، هذه الوظائف لا صحة مدخلاتها. مع كل تعطيك القمامة إذا كان هذا هو ما يحصل.

وإليك ما خطرت لي.

/// <summary>
/// Return an incremented alphabtical string
/// </summary>
/// <param name="letter">The string to be incremented</param>
/// <returns>the incremented string</returns>
public static string NextLetter(string letter)
{
  const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  if (!string.IsNullOrEmpty(letter))
  {
    char lastLetterInString = letter[letter.Length - 1];

    // if the last letter in the string is the last letter of the alphabet
    if (alphabet.IndexOf(lastLetterInString) == alphabet.Length - 1) 
    {
        //replace the last letter in the string with the first leter of the alphbat and get the next letter for the rest of the string
        return NextLetter(letter.Substring(0, letter.Length - 1)) + alphabet[0];
    }
    else 
    {
      // replace the last letter in the string with the proceeding letter of the alphabet
      return letter.Remove(letter.Length-1).Insert(letter.Length-1, (alphabet[alphabet.IndexOf(letter[letter.Length-1])+1]).ToString() );
    }
  }
  //return the first letter of the alphabet
  return alphabet[0].ToString();
}

ومجرد لافتة، لماذا لا فقط

    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];
         }
    }

وهذا هو مثل عرض عدد صحيح، فقط باستخدام قاعدة 26 بدلا من قاعدة 10. حاول الخوارزمية التالية للعثور على دخول الألف من مجموعة

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;
}

وبطبيعة الحال، إذا كنت ترغب في إدخالات ن الأولى، ليس هذا هو الحل الأكثر فعالية. في هذه الحالة، في محاولة شيء من هذا القبيل حل دانيال.

وأعطى هذا التوجه، وجاء مع هذا:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Alphabetty
{
    class Program
    {
        const string alphabet = "abcdefghijklmnopqrstuvwxyz";
        static int cursor = 0;
        static int prefixCursor;
        static string prefix = string.Empty;
        static bool done = false;
        static void Main(string[] args)
        {
            string s = string.Empty;
            while (s != "Done")
            {
                s = GetNextString();
                Console.WriteLine(s);
            }
            Console.ReadKey();

        }        
        static string GetNextString()
        {
            if (done) return "Done";
            char? nextLetter = GetNextLetter(ref cursor);
            if (nextLetter == null)
            {
                char? nextPrefixLetter = GetNextLetter(ref prefixCursor);
                if(nextPrefixLetter == null)
                {
                    done = true;
                    return "Done";
                }
                prefix = nextPrefixLetter.Value.ToString();
                nextLetter = GetNextLetter(ref cursor);
            }

            return prefix + nextLetter;
        }

        static char? GetNextLetter(ref int letterCursor)
        {
            if (letterCursor == alphabet.Length)
            {
                letterCursor = 0;
                return null;
            }

            char c = alphabet[letterCursor];
            letterCursor++;
            return c;
        }
    }
}

وهنا شيء كنت قد يطبخ التي قد تكون مشابهة. كنت تجريب التهم التكرار من أجل تصميم مخطط الترقيم الذي كان صغيرا قدر الإمكان، ولكن أعطاني ما يكفي من التفرد.

وكنت أعرف أن في كل مرة وأضاف الطابع ألفا، فمن شأنه أن يزيد من احتمالات 26X ولكن لم أكن متأكدا من عدد الحروف والأرقام، أو نمط أردت أن استخدام.

وهذا يقودني إلى رمز أدناه. في الأساس تمريرها سلسلة AlphaNumber، وكل موقف له رسالة، فإن زيادة في النهاية إلى "Z \ Z" وكل موقف التي كان لها عدد، فإن زيادة في النهاية إلى "9".

وهكذا يمكنك تسميتها 1 من ناحيتين ..

//This would give you the next Itteration... (H3reIsaStup4dExamplf)
string myNextValue = IncrementAlphaNumericValue("H3reIsaStup4dExample") 

//Or Loop it resulting eventually as "Z9zzZzzZzzz9zZzzzzzz"
string myNextValue = "H3reIsaStup4dExample"
while (myNextValue != null)
{
   myNextValue = IncrementAlphaNumericValue(myNextValue)
   //And of course do something with this like write it out
}

و(بالنسبة لي، كنت تفعل شيئا مثل "1AA000")

public string IncrementAlphaNumericValue(string Value)
    {
        //We only allow Characters a-b, A-Z, 0-9
        if (System.Text.RegularExpressions.Regex.IsMatch(Value, "^[a-zA-Z0-9]+$") == false)
        {
            throw new Exception("Invalid Character: Must be a-Z or 0-9");
        }

        //We work with each Character so it's best to convert the string to a char array for incrementing
        char[] myCharacterArray = Value.ToCharArray();

        //So what we do here is step backwards through the Characters and increment the first one we can. 
        for (Int32 myCharIndex = myCharacterArray.Length - 1; myCharIndex >= 0; myCharIndex--)
        {
            //Converts the Character to it's ASCII value
            Int32 myCharValue = Convert.ToInt32(myCharacterArray[myCharIndex]);

            //We only Increment this Character Position, if it is not already at it's Max value (Z = 90, z = 122, 57 = 9)
            if (myCharValue != 57 && myCharValue != 90 && myCharValue != 122)
            {
                myCharacterArray[myCharIndex]++;

                //Now that we have Incremented the Character, we "reset" all the values to the right of it
                for (Int32 myResetIndex = myCharIndex + 1; myResetIndex < myCharacterArray.Length; myResetIndex++)
                {
                    myCharValue = Convert.ToInt32(myCharacterArray[myResetIndex]);
                    if (myCharValue >= 65 && myCharValue <= 90)
                    {
                        myCharacterArray[myResetIndex] = 'A';
                    }
                    else if (myCharValue >= 97 && myCharValue <= 122)
                    {
                        myCharacterArray[myResetIndex] = 'a';
                    }
                    else if (myCharValue >= 48 && myCharValue <= 57)
                    {
                        myCharacterArray[myResetIndex] = '0';
                    }
                }

                //Now we just return an new Value
                return new string(myCharacterArray);
            } 
        }

        //If we got through the Character Loop and were not able to increment anything, we retun a NULL. 
        return null;  
    }

إليك محاولتي باستخدام العودية:

public static void PrintAlphabet(string alphabet, string prefix)
{
    for (int i = 0; i < alphabet.Length; i++) {
        Console.WriteLine(prefix + alphabet[i].ToString());
    }

    if (prefix.Length < alphabet.Length - 1) {
        for (int i = 0; i < alphabet.Length; i++) {
            PrintAlphabet(alphabet, prefix + alphabet[i]);
        }
    }
}

وبعد ذلك مجرد دعوة PrintAlphabet("abcd", "")؛

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top