examples - for next step c#
Iterando a través del alfabeto-C#a-caz (10)
Aquí está mi intento de usar la recursión:
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]);
}
}
}
Luego simplemente llame a PrintAlphabet("abcd", "")
;
Tengo una pregunta acerca de iterar a través del alfabeto. Me gustaría tener un bucle que comienza con "a" y termina con "z". Después de eso, el bucle comienza "aa" y cuenta hasta "az". después de eso comienza con "ba" hasta "bz" y así sucesivamente ...
¿Alguien sabe alguna solución?
Gracias
EDITAR: Olvidé que le doy un carácter "a" a la función, luego la función debe devolver b. si da "bnc" entonces la función debe devolver "bnd"
Aquí hay algo que he cocinado que puede ser similar. Estaba experimentando con recuentos de iteraciones para diseñar un esquema de numeración que fuera lo más pequeño posible, pero que me diera la suficiente singularidad.
Sabía que cada vez que se añadía un carácter alfa, aumentaba las posibilidades 26x, pero no estaba seguro de cuántas letras, números o el patrón quería usar.
Eso me llevó al código de abajo. Básicamente, se le pasa una cadena AlphaNumber, y cada posición que tiene una letra, eventualmente se incrementará a "z / Z" y cada posición que tenga un número, eventualmente se incrementará a "9".
Así que puedes llamarlo 1 de dos maneras ..
//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
}
(Para mí, estaba haciendo algo como "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;
}
Esto es como mostrar un int, usando solo la base 26 en lugar de la base 10. Pruebe el siguiente algoritmo para encontrar la entrada nth de la matriz
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;
}
Por supuesto, si desea las primeras n entradas, esta no es la solución más eficiente. En este caso, intente algo como la solución de daniel.
Esto es lo que se me ocurrió.
/// <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();
}
Le di una oportunidad a esto y se me ocurrió esto:
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;
}
}
}
Lo siguiente llena una lista con las cadenas requeridas:
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());
}
}
Sé que hay muchas respuestas aquí, y que han sido aceptadas, pero OMI, todas lo hacen más difícil de lo que debe ser. Creo que lo siguiente es más sencillo y limpio:
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);
}
Tenga en cuenta que esto no hace ninguna validación de entrada. Si no confía en sus interlocutores, debe agregar un cheque IsNullOrEmpty
al principio, y una c[i] >= ''A'' && c[i] <= ''Z'' || c[i] >= ''a'' && c[i] <= ''z''
c[i] >= ''A'' && c[i] <= ''Z'' || c[i] >= ''a'' && c[i] <= ''z''
marque en la parte superior del bucle. O simplemente déjalo ser y deja que sea GIGO .
También puede encontrar uso para estas funciones complementarias:
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;
}
Estas dos funciones están basadas en cero. Es decir, "A" = 0, "Z" = 25, "AA" = 26, etc. Para convertirlos en una base (como la interfaz COM de Excel), elimine la línea sobre la línea comentada en cada función y elimine los comentarios líneas.
Al igual que con la función NextColumn
, estas funciones no validan sus entradas. Ambos con darte basura si eso es lo que consiguen.
solo por curiosidad, por que no solo
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];
}
}
Edición: Hizo que hiciera exactamente lo que quiere la última edición del OP.
Esta es la solución más simple, y probada:
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;
}
Primer esfuerzo, con solo az entonces 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);
}
}
}
Tenga en cuenta que esto se detendrá en ''zz''. Por supuesto, hay una duplicación fea aquí en términos de los bucles. Afortunadamente, es fácil de solucionar, y también puede ser aún más flexible:
Segundo intento: alfabeto más flexible.
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);
}
}
}
Ahora, si desea generar solo a, b, c, d, aa, ab, ac, ad, ba, ... llamaría a GetExcelColumns("abcd")
.
Tercer intento (revisado más adelante) - secuencia infinita
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 posible que sea un código más limpio utilizando la recursión, pero no sería tan eficiente.
Tenga en cuenta que si desea detenerse en un cierto punto, simplemente puede usar LINQ:
var query = GetExcelColumns().TakeWhile(x => x != "zzz");
"Reiniciando" el iterador
Para reiniciar el iterador desde un punto dado, puede utilizar SkipWhile
como lo sugiere thesoftwarejedi. Eso es bastante ineficiente, por supuesto. Si puede mantener cualquier estado entre llamadas, solo puede mantener el iterador (para cualquiera de las soluciones):
using (IEnumerator<string> iterator = GetExcelColumns())
{
iterator.MoveNext();
string firstAttempt = iterator.Current;
if (someCondition)
{
iterator.MoveNext();
string secondAttempt = iterator.Current;
// etc
}
}
De manera alternativa, puede ser capaz de estructurar su código para usar un foreach
todos modos, simplemente rompiendo el primer valor que realmente puede usar.