Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Increment a value from AAA to ZZZ with cyclic rotation

Tags:

c#

increment

I need to code a method that increment a string value from AAA to ZZZ with cyclic rotation (next value after ZZZ is AAA)

Here is my code:

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

I know this piece of code is quite dirty and not very efficient but I dont know how to do it properly.

How is secured this snippet? (this will only run on windows plaform)

How can I optimize-it and make it more readable ?

Thanks for your comments

like image 898
fxkim Avatar asked Jun 15 '10 16:06

fxkim


3 Answers

Think about it mathematically: Your strings (AAA, AAB, ...) behave just like natural numbers (000, 001, ...), with the exception of being base 26 instead of base 10.

So, you can use the same principle. Here is some code:

// 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();
}
like image 99
Heinzi Avatar answered Nov 19 '22 04:11

Heinzi


Perhaps I'm missing something, but I think this reasonably trivial solution works, and not just for three digit numbers; any arbitary length base 26 number can be incremented. It will wrap from ZZZZ to AAAA as per the question, rather than incrementing "correctly" from ZZZZ to 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);
}
like image 20
meagar Avatar answered Nov 19 '22 04:11

meagar


I think it's easier to parse it to an integer, do the increment, then format the result as a string. Note that if you just need to iterate over the numbers to generate the range of combinations, then you don't really need the increment/parse. You can simply have a for loop on the integer range and use the format method to convert the integer to a string.

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];
}
like image 30
tvanfosson Avatar answered Nov 19 '22 03:11

tvanfosson