Frage

Ich habe eine Frage zu iterieren durch das Alphabet. Ich möchte eine Schleife haben, die mit „a“ beginnt und endet mit „z“. Danach beginnt die Schleife „aa“ und zählt zu „az“. danach beginnt mit „ba“ bis zu „bz“ und so weiter ...

Wer etwas Lösung wissen?

Danke

EDIT: Ich habe vergessen, dass ich ein Zeichen „a“ an die Funktion geben dann muss die Funktion zurückgeben b. wenn u geben „bnc“ dann muss die Funktion zurückgeben „bnd“

War es hilfreich?

Lösung

Edit: es genau so, wie die letzte bearbeiten die OP gemacht tun will

Dies ist die einfachste Lösung und getestet:

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

Andere Tipps

Erste Bemühungen, mit nur einem-z dann 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);
        }
    }
}

Beachten Sie, dass dies bei ‚zz‘ zu stoppen. Natürlich gibt es einige hässliche Duplikation hier in Bezug auf den Schleifen. das ist zum Glück einfach zu beheben - und es kann noch flexibler sein, auch:

Zweiter Versuch: flexibleren 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);
        }
    }
}

Nun, wenn Sie nur a, b, c, d, aa, ab, ac, ad, ba, generieren möchten ... Sie GetExcelColumns("abcd") nennen würde.

dritter Versuch (überarbeitet weiter) - unendliche Folge

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

Es ist möglich, dass es sauberen Code Rekursion sein würde, aber es wäre nicht so effizient sein.

Beachten Sie, dass, wenn Sie an einem bestimmten Punkt stoppen wollen, können Sie einfach LINQ verwenden:

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

"Neustart" der Iterator

den Iterator von einem gegebenen Punkt neu zu starten, könnte man in der Tat verwenden SkipWhile wie TheSoftwareJedi vorgeschlagen. Das ist ziemlich ineffizient, natürlich. Wenn Sie irgendeinen Zustand zwischen Anruf zu halten sind in der Lage, können Sie einfach den Iterator halten (für beide Lösung):

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

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

Alternativ können Sie auch in der Lage sein, Ihren Code zu strukturieren ein foreach trotzdem zu verwenden, bricht nur auf dem ersten Wert aus Sie tatsächlich nutzen können.

In der folgenden auffüllt eine Liste mit den erforderlichen 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());
    }
}

Ich weiß, es gibt viele Antworten sind hier, und man ist akzeptiert worden, aber IMO alles, was sie machen es schwieriger, als es sein muss. Ich denke, die folgende ist einfacher und sauberer:

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

Beachten Sie, dass dies keine Eingabevalidierung macht. Wenn Sie nicht über Ihre Anrufer vertrauen, sollten Sie eine IsNullOrEmpty Prüfung am Anfang, und eine c[i] >= 'A' && c[i] <= 'Z' || c[i] >= 'a' && c[i] <= 'z' Prüfung an der Spitze der Schleife hinzuzufügen. Oder lass es einfach sein und lassen Sie es sein GIGO .

Sie können auch Gebrauch für diese Begleiter Funktionen:

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

Diese beiden Funktionen sind nullbasiert. Das heißt, „A“ = 0, „Z“ = 25, „AA“ = 26, usw., um sie eine Basis (wie Excel COM-Schnittstelle), entfernen Sie die Zeile oberhalb der Kommentarzeile in jeder Funktion zu machen, und Kommentar- diejenigen Linien.

Wie bei der NextColumn Funktion, diese Funktionen validieren nicht ihre Eingänge. Sowohl mit Ihnen Müll, wenn das ist, was sie bekommen.

Hier ist, was ich kam mit.

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

einfach nur neugierig, warum nicht nur

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

Das ist wie ein int anzeigt, nur Base 26 anstelle von Basis 10 den folgenden Algorithmus Versuchen Sie, den n-te Eintrag des Arrays zu finden

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

Natürlich, wenn Sie die ersten n Einträge wollen, ist dies nicht die effizienteste Lösung. In diesem Fall versuchen Sie so etwas wie daniel-Lösung.

Ich habe diese ein zu gehen und kam mit dieser:

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

Hier ist etwas, das ich gekocht hatte, bis die ähnlich sein können. Ich war mit Iteration zählt, um das Experimentieren ein Nummerierungsschema zu entwerfen, die so klein wie möglich war, noch gab mir genug Einzigartigkeit.

wusste ich, dass jedes Mal, wenn ein ein Alpha Zeichen hinzugefügt, wäre es die Möglichkeiten 26x zu erhöhen, aber ich war nicht sicher, wie viele Buchstaben, Zahlen oder das Muster, das ich verwenden wollte.

Das bin ich zu dem Code führen unten. Grundsätzlich Sie es einen AlphaNumber String, und jede Position, die einen Brief hat, würde schließlich zu „z \ Z“ erhöhen und jeder Position, die eine Nummer hatte, würde schließlich auf „9“ erhöht.

So können Sie es 1 von zwei Arten aufrufen ..

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

(Für mich ich tat so etwas wie "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;  
    }

Hier ist mein Versuch mit Rekursion:

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

Dann einfach PrintAlphabet("abcd", "") nennen;

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top