2010-06-15 13 views
10

ho bisogno di codificare un metodo che incrementa un valore stringa da AAA a Zzz con rotazione ciclica (prossimo valore dopo ZZZ è AAA)Incremento un valore da AAA a Zzz con rotazione ciclica

Ecco il mio codice:

public static string IncrementValue(string value) { 
     if (string.IsNullOrEmpty(value) || value.Length != 3) { 
      string msg = string.Format("Incorrect value ('{0}' is not between AAA and ZZZ)", value); 
      throw new ApplicationException(msg); 
     } 
     if (value == "ZZZ") { 
      return "AAA"; 
     } 
     char pos1 = value[0]; 
     char pos2 = value[1]; 
     char pos3 = value[2]; 

     bool incrementPos2 = false; 
     bool incrementPos1 = false; 

     if (pos3 == 'Z') { 
      pos3 = 'A'; 
      incrementPos2 = true; 
     } else { 
      pos3++; 
     } 

     if (incrementPos2 && pos2 == 'Z') { 
      pos2 = 'A'; 
      incrementPos1 = true; 
     } else { 
      if (incrementPos2) { 
       if (pos2 == 'Z') { 
        pos2 = 'A'; 
        incrementPos1 = true; 
       } 
       pos2++; 
      } 
     } 

     if (incrementPos1) { 
      pos1++; 
     } 

     return pos1.ToString() + pos2.ToString() + pos3.ToString(); 
    } 

So che questo pezzo di codice è piuttosto sporco e non molto efficiente, ma non so come farlo correttamente.

Come è protetto questo snippet? (questo verrà eseguito solo su windows plaform)

Come ottimizzare e rendere più leggibile?

Grazie per i vostri commenti

+4

Perché non utilizzare base-26 numero? – kennytm

+0

Hai davvero bisogno di un metodo di incremento o potresti ad es. un lavoro ripetitivo di iteratore infinito? –

+0

@Matthew Stai suggerendo di creare una lista circolare contenente i valori AAA..ZZZ? Sarà una bella lista. – meagar

risposta

17

Pensateci matematicamente: I suoi archi (AAA, AAB, ...) si comportano proprio come i numeri naturali (000, 001, ...), con l'eccezione di essere base 26 invece della base 10.

Quindi, è possibile utilizzare lo stesso principio. Ecco il codice:

// iterate cyclicly from 0 to 26^3 - 1 
int incrementValue(int i) { 
    // a verbose way of writing "return (i + 1) % 26^3" 
    i++; 
    if (i == 26*26*26) i = 0; 
    return i; 
} 

// convert 0 to AAA, 1 to AAB, ... 
string formatValue(int i) { 
    var result = new StringBuilder(); 

    result.Insert(0, (char)('A' + (i % 26))); 
    i /= 26; 
    result.Insert(0, (char)('A' + (i % 26))); 
    i /= 26; 
    result.Insert(0, (char)('A' + (i % 26))); 

    return result.ToString(); 
} 
+0

mi piace, esegue l'incrementazione su un intero semplice e converte basare-26 on notazione richiesta. Una leggera performance, però, con tutta questa ulteriore divisione. – meagar

+0

@meagar: una divisione è una semplice istruzione della macchina. La creazione dell'istanza StringBuilder ad esempio costa * modo * più delle divisioni. – Guffa

+0

@Guffa Era sotto l'impressione che la divisione fosse intrinsecamente più costosa dell'aggiunta, ma la mia conoscenza è certamente datata; Al giorno d'oggi non passo il tempo nelle lingue di livello inferiore. – meagar

1

Penso che sia più facile da analizzare in un numero intero, faccio l'incremento, quindi formattare il risultato sotto forma di stringa. Nota che se hai solo bisogno di scorrere i numeri per generare l'intervallo di combinazioni, allora non hai davvero bisogno dell'incremento/analisi. È sufficiente avere un ciclo for nell'intervallo intero e utilizzare il metodo format per convertire il numero intero in una stringa.

public static string IncrementValue(string value) { 
    if (string.IsNullOrEmpty(value) || value.Length != 3) { 
     string msg = string.Format("Incorrect value ('{0}' is not between AAA and ZZZ)", value); 
     throw new ApplicationException(msg); 
    } 
    if (value == "ZZZ") { 
     return "AAA"; 
    } 
    int thisValue = Parse(value); 
    thisValue = (thisValue + 1) % 17576; // 26 * 26 * 26 
    return Format(thisValue); 
} 

private static int Parse(string value) 
{ 
    int result = 0; 
    foreach (var c in value) 
    { 
     result += ('Z' - c); // might need to cast to int? 
    } 
    return result; 
} 

private static string[] Alphabet = new string[] { 'A', 'B', ... }; 
private static string Format(int value) 
{ 
    int digit0 = value % 26; 
    int digit1 = (value/26) % 26; 
    int digit2 = value/676; 
    return Alphabet[digit2] + Alphabet[digit1] + Alphabet[digit0]; 
} 
11

Forse mi manca qualcosa, ma penso che questa soluzione ragionevolmente banale funziona, e non solo per numeri a tre cifre; qualsiasi numero base 26 di lunghezza arbitary può essere incrementato. Si avvolgerà da ZZZZ a AAAA come da domanda, invece di incrementare "correttamente" da ZZZZ a AAAAA.

// Increment a base 26 number (composed of "digits" A..Z), wrapping around 
// from ZZZ... to AAA... 
string increment(string str) {   
    char[] digits = str.ToCharArray(); 

    for (int i = str.length - 1; i >= 0; --i) { 
    if (digits[i] == 'Z') { 
     digits[i] = 'A'; 
    } else { 
     digits[i] += 1; 
     break; 
    } 
    } 
    return new string(digits); 
} 
+2

+1, una simpatica e compatta generalizzazione algoritmica dell'algoritmo "aggiungi" che abbiamo imparato all'asilo. BTW: La correzione da I a 3 ti consentirebbe di rilasciare il comando 'if' all'inizio del metodo e darebbe come risultato un avvolgimento" naturale ". – Heinzi

+0

@Heinzi Sì, rimosso. L'algoritmo per questo tipo specializzato di incremento continua a diventare più semplice più ci penso. È semplice come lo sarà ora ... – meagar

+0

Grazie Meagar per il tuo pezzo di codice. È compatto, semplice e chiaro. Questo modo per risolvere il mio problema è davvero "elegante"! – fxkim

-1

in 'C' ho scritto il seguente che farà esattamente come richiesto, vale a dire data AA aumenterà di AB. Dato ZZZ aumenterà a AAA (ciclo).

main(int argc, char **argv) 
{ 

    int i; 
    char *s = argv[1]; 

    for(i=strlen(s)-1; i >= 0; i--) { 
      if(++s[i] > 'Z') 
       s[i] = 'A'; 
      else 
       break; 
    } 

    printf("%s\n",s); 
} 
+0

C# non è C. Oltre ad alcune somiglianze nella sintassi, non condividono praticamente nulla. – meagar

-1
import java.util.*; 

import java.io.*; 

public class abc{ 

public static void main (String arg[])throws Exception{ 

int i; 

String s; 

BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 

System.out.println("...");\\just for get length of vector example 3 for aaa to zzz 
i= Integer.parseInt(br.readLine()); 
char[] guess = new char[i]; 

Arrays.fill(guess, 'a'); 


do { 
System.out.println("Current guess: " + new String(guess)); 


int n = guess.length - 1; 

while (n >= 0) { 

guess[n]++; 

if (guess[n] > 'z') { 

       if (n > 0) { 

        guess[n] = 'a'; 

       } 

       n--; 

      } 

    else { 

       break; 

      } 

     } 


    } 
while (guess[0] <= 'z'); 

} 
+0

Questa è una domanda C#, non una domanda Java. – meagar