문제

알파벳 반복에 대한 질문이 있습니다."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;
}

다른 팁

첫 번째 노력, AZ만으로 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' 루프 상단에서 확인하십시오.아니면 그냥 내버려두고 그대로 두세요. 지고.

다음과 같은 동반 기능을 사용할 수도 있습니다.

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

이 두 함수는 0부터 시작합니다.즉, "A" = 0, "Z" = 25, "AA" = 26 등입니다.Excel의 COM 인터페이스와 같이 1개 기반으로 만들려면 각 함수에서 주석 처리된 줄 위의 줄을 제거하고 해당 줄의 주석 처리를 제거합니다.

와 마찬가지로 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];
         }
    }

이것은베이스 10의 대신베이스 26 만 사용하는 int를 표시하는 것과 같습니다. 다음 알고리즘을 시도하여 배열의 N 번째 항목을 찾으십시오.

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

물론 첫 번째 N 항목을 원한다면 이것이 가장 효율적인 솔루션이 아닙니다. 이 경우 Daniel의 솔루션과 같은 것을 시도하십시오.

나는 이것을 가서 이것을 생각해 냈다 :

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

여기에 내가 비슷한 요리를 한 것이 있습니다. 나는 가능한 한 작았지만 충분한 독창성을 주었다.

나는 알파 문자를 추가 할 때마다 가능성이 26 배를 증가시킬 것이라는 것을 알았지 만 글자, 숫자 또는 내가 사용하고 싶은 패턴을 확신하지 못했습니다.

그것은 아래 코드로 이어집니다. 기본적으로 당신은 그것을 alphanumber 문자열로 전달하고, 문자가있는 모든 위치는 결국 "z z"로 증가하고 숫자가있는 모든 위치는 결국 "9"로 증가합니다.

그래서 당신은 그것을 두 가지 방법 중 하나라고 부를 수 있습니다 ..

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