2

I'm trying to create a sequence of numbers in string format, once I reach "99999" I want to continue the sequence using leading letters.

Example:

"00000" -> "00100" -> "99999" -> "A0001" -> "A9999" -> "B0001" -> "ZZZZZ"

Is there an easy way to achieve this ?

So far I tried to split my string in numbers and letters and then I have some code cheking if numbers reach maximum, if it reach the maximum available I add a letter. Doesn't look really elegant to me.

5
  • what have you tried so far? which problem has _you _ encountered? Commented Dec 19, 2018 at 11:19
  • You can use ascii values to do that Commented Dec 19, 2018 at 11:20
  • added what i tried so far Commented Dec 19, 2018 at 11:23
  • Please, confirm or put the right rule when changing: Z9999 -> AA001? AZ999 -> BA001? Commented Dec 19, 2018 at 11:25
  • 1
    You want modular 36 arithmetic (0-9,A-Z). Your sequence should be 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H, I, J, K,L,M,N,O,P,Q,R,S,T,UV,W,X,Y,Z. Commented Dec 19, 2018 at 11:29

2 Answers 2

5

Let's implement GetNextValue method: for a given value (e.g. "A9999") we compute the next ("B0001"):

private static string GetNextValue(string value) {
  StringBuilder sb = new StringBuilder(value);

  // Digits only: 1239 -> 1240
  for (int i = value.Length - 1; i >= 0; --i) {
    if (sb[i] < '9') {
      sb[i] = (char)(sb[i] + 1);

      return sb.ToString();
    }
    else if (sb[i] >= 'A')
      break;
    else
      sb[i] = '0';
  }

  // 1st letter: 9999 -> A001
  if (sb[0] == '0') {
    sb[0] = 'A';

    if (sb[sb.Length - 1] == '0')
      sb[sb.Length - 1] = '1';

    return sb.ToString();
  }

  // Leading letters AZ999 -> BA001
  for (int i = value.Length - 1; i >= 0; --i) {
    if (sb[i] >= 'A') {
      if (sb[i] < 'Z') {
        sb[i] = (char)(sb[i] + 1);

        if (sb[sb.Length - 1] == '0')
          sb[sb.Length - 1] = '1';

        return sb.ToString();
      }
      else
        sb[i] = 'A';
    }
  }

  // All letters increment: ABCDZ -> ABCEA
  for (int i = 0; i < value.Length; ++i) {
    if (sb[i] == '0') {
      sb[i] = 'A';

      if (sb[sb.Length - 1] == '0')
        sb[sb.Length - 1] = '1';

      return sb.ToString();
    }
  }

  // Exhausting: ZZZZZ -> 00000
  return new string('0', value.Length);
}

If you want to enumerate these values:

private static IEnumerable<string> Generator(int length = 5) {
  string item = new string('0', length);

  do {
    yield return item;

    item = GetNextValue(item);
  }
  while (!item.All(c => c == '0'));
}

Demo: (let's use a string of length 3)

Console.Write(string.Join(Environment.NewLine, Generator(3)));

Outcome: (27234 items in total; 18769482 items if length == 5)

000
001
002
...
009
010
...
999
A01
...
A99
B01
...
Z99
AA1
...
AA9
AB1
...
AZ9
BA1
...
ZZ9
AAA
AAB
AAC
...
AAZ
ABA
...
ZZY
ZZZ
Sign up to request clarification or add additional context in comments.

Comments

0

Here is an extension method which formats integer values to your format (with leading letters):

public static string ToZormat(this int value, int length = 5)
{
    string map = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    char[] result = new char[length];
    var x = value;

    for(int i = 0; i < length; i++)
    {
        int threshold = (int)Math.Pow(10, length - i - 1);
        var index = Math.Min(map.Length - 1, x / threshold);
        result[i] = map[index];
        x -= threshold * index;
    }

    return new String(result);
}

When you have number formatted to a string of length 5, leading letters appear after value 99,999, next go A0,000, ... A9,999, B0,000 etc. As you can see the first character changes every 10,000 numbers. The second character changes every 1,000 numbers. And last, the fifth character will change for every number. We just need to implement that algorithm.

Basic steps:

  • Define map of characters which are used in your format
  • Calculate character change threshold for the current position (i) - it will be power of 10: 10,000, 1,000, 100, 10, 1.
  • Get the index of character from map. Its simply number of thresholds which fits the value, but not more than the number of characters in your map.
  • Calculate what's left from input value and go to next postion

You should add validation for the max value which fits the given length of the formatted string.


Sample for length 3:

Enumerable.Range(0, 3886).Select(x => x.ToZormat(3))

Output:

000
001
002
...
999
A00
A01
...
A99
B00
B01
...
Z99
ZA0
ZA1
...
ZZ9
ZZA
...
ZZZ

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.