Я должен кодировать метод, которые увеличивают строковое значение от AAA до ZZZ с циклическим вращением (следующее значение после того, как ZZZ является AAA),
Вот мой код:
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();
}
Я знаю, что эта часть кода довольно грязна и не очень эффективна, но я не знаю, как сделать это правильно.
Как защищается этот отрывок? (это будет только работать на plaform окон),
Как я могу оптимизировать - это и сделать это более читаемым?
Спасибо за Ваши комментарии
Подумайте об этом математически: ваши строки (AAA, AAB, ...) ведут себя точно так же, как натуральные числа (000, 001, ...), за исключением того, что они являются основанием 26 вместо 10.
Итак , вы можете использовать тот же принцип. Вот код:
// 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();
}
Я думаю, что проще разобрать его до целого числа, сделать инкремент, а затем отформатировать результат как строку. Обратите внимание, что если вам нужно просто итерировать числа для создания диапазона комбинаций, то инкремент/разбор вам не нужен. Вы можете просто выполнить цикл for
для целочисленного диапазона и использовать метод format для преобразования целого числа в строку.
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];
}
Возможно, я что-то упускаю, но я думаю, что это достаточно тривиальное решение работает, и не только для трехзначных чисел; любое число произвольной длины с основанием 26 может быть увеличено. Он будет переходить от ZZZZ к AAAA в соответствии с вопросом, вместо того, чтобы «правильно» увеличиваться от ZZZZ до 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);
}