Question

J'ai une question à propos de l'itération dans l'alphabet. J'aimerais avoir une boucle qui commence par & "; Un &"; et se termine par & "; z &"; Après cela, la boucle commence & Quot; aa & Quot; et comptez jusqu'à & "; az &"; après cela commence par " ba " jusqu'à " bz " et ainsi de suite ...

Quelqu'un connaît une solution?

Merci

EDIT: J'ai oublié de donner un caractère & "; un &"; à la fonction alors la fonction doit retourner b. si u donne " bnc " alors la fonction doit renvoyer & "; bnd &";

Était-ce utile?

La solution

Edit: faites-le exactement comme le veut le dernier montage de l'OP

C’est la solution la plus simple et testée:

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

Autres conseils

Premier effort, avec a-z puis 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);
        }
    }
}

Notez que cela s’arrêtera à "zz". Bien sûr, il y a un certain dédoublement moche en termes de boucles. Heureusement, c'est facile à corriger - et cela peut être encore plus flexible:

Deuxième tentative: alphabet plus souple

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

Maintenant, si vous voulez générer juste un b, c, d, aa, ab, ac, ad, ba, ... vous appelleriez GetExcelColumns("abcd").

Troisième tentative (révisée plus loin) - séquence infinie

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

Il est possible que ce soit un code plus propre utilisant la récursivité, mais ce ne serait pas aussi efficace.

Notez que si vous souhaitez vous arrêter à un moment donné, vous pouvez simplement utiliser LINQ:

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

" Redémarrer " l'itérateur

Pour redémarrer l'itérateur à partir d'un point donné, vous pouvez en effet utiliser SkipWhile comme suggéré par le logiciel jedi. C'est assez inefficace, bien sûr. Si vous pouvez conserver n'importe quel état entre les appels, vous pouvez simplement conserver l'itérateur (quelle que soit la solution):

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

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

Alternativement, vous pourrez peut-être structurer votre code de manière à utiliser un foreach de toute façon, juste en sortant de la première valeur que vous pouvez réellement utiliser.

Ce qui suit remplit une liste avec les chaînes requises:

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

Je sais que les réponses ne manquent pas et que les réponses ont été acceptées, mais l’OMI rend toutes les choses plus difficiles. Je pense que ce qui suit est plus simple et plus propre:

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

Notez que cela ne fait aucune validation d’entrée. Si vous ne faites pas confiance à vos appelants, vous devez ajouter une coche IsNullOrEmpty au début et une coche c[i] >= 'A' && c[i] <= 'Z' || c[i] >= 'a' && c[i] <= 'z' en haut de la boucle. Vous pouvez également le laisser être GIGO .

Vous pouvez également trouver une utilisation pour ces fonctions complémentaires:

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

Ces deux fonctions sont basées sur zéro. C’est-à-dire & "A &"; = 0, & Quot; Z & Quot; = 25, & Quot; AA & Quot; = 26, etc. Pour les rendre uniques (comme l'interface COM d'Excel), supprimez la ligne située au-dessus de la ligne commentée dans chaque fonction et décommentez ces lignes.

Comme avec la fonction NextColumn, ces fonctions ne valident pas leurs entrées. Les deux avec vous donner des ordures si c'est ce qu'ils obtiennent.

Voici & # 8217; ce que j'ai proposé.

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

simplement curieux, pourquoi ne pas simplement

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

Cela ressemble à l’affichage d’un entier, utilisant uniquement la base 26 au lieu de la base 10. Essayez l’algorithme suivant pour trouver la nième entrée du tableau

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

Bien sûr, si vous voulez les n premières entrées, ce n’est pas la solution la plus efficace. Dans ce cas, essayez quelque chose comme la solution de Daniel.

J'ai essayé ceci et suis venu avec ceci:

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

Voici quelque chose que j'avais concocté qui pourrait être similaire. J'essayais de compter les itérations afin de concevoir un schéma de numérotation aussi petit que possible, tout en me laissant suffisamment d'unicité.

Je savais que chaque fois qu'un caractère Alpha était ajouté, les possibilités étaient multipliées par 26, mais je ne savais pas trop combien de lettres, de chiffres ou du motif que je voulais utiliser.

Cela m’amène au code ci-dessous. En gros, vous lui transmettez une chaîne AlphaNumber et chaque position comportant une lettre est incrémentée de & "; Z \ Z &"; et chaque position qui avait un nombre, finirait par augmenter de & "; 9 &";.

.

Vous pouvez donc l'appeler de deux manières différentes.

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

(Pour moi, je faisais quelque chose comme & "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;  
    }

Voici ma tentative d'utilisation de la récursivité:

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

Ensuite, appelez simplement PrintAlphabet("abcd", "");

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top