I was given the problem (called "car plate problem") to write all the values that go from AAA0001 to ZZZ9999 with the following premises:
- Create all the possibilities from AAA0001 to ZZZ9999;
- Skip all the 0000, ie: AAB0000, AAC0000... ZZZ0000.
- No repetitions. Once a value is "created" or "found", whatever, the value cannot repeat. So, once your code generated the AAA0002, it shouldn't generate the AAA0002 again.
So... I found a solution (posted below). It was "short" and "oh boy" it was weak! But I was coding against time so I had to go with that solution. I recognize the solution lacks creativity, better use of O.O. and probably there is a design pattern to be use here. None I could identify but still, there must be a better way to make it work. Is there a solution with better code quality and (if possible) less processing?
public class PlateIncrement {
private String plate;
public PlateIncrement () {
}
public void setPlate(String thePlate) {
plate = thePlate;
}
public String getIncrementedPlate() {
String finalNumber = "";
String finalLetters = "";
String letters = plate.substring(0,3);
String numbers = plate.substring(3,7);
letters = letters.toUpperCase();
if (Integer.parseInt(numbers) != 9999) {
finalNumber = incrementNumber(numbers);
finalLetters = letters;
} else {
finalLetters = getIncrementedLetters(letters);
finalNumber = "0001";
}
return finalLetters.concat(finalNumber);
}
private String getIncrementedLetters(String letters) {
String[] splittedLetters = letters.split("");
if( !splittedLetters[2].equalsIgnoreCase("Z") ) {
incrementLetter(splittedLetters, 2);
} else if( !splittedLetters[1].equalsIgnoreCase("Z") ) {
incrementLetter(splittedLetters, 1);
splittedLetters[2] = "A";
} else if( !splittedLetters[0].equalsIgnoreCase("Z") ) {
incrementLetter(splittedLetters, 0);
splittedLetters[2] = "A";
splittedLetters[1] = "A";
}
return String.join("", splittedLetters);
}
private void incrementLetter(String[] splittedLetters, int i) {
char theChar = splittedLetters[i].charAt(0);
char incrementedChar = (char) (theChar + 1);
splittedLetters[i] = String.valueOf(incrementedChar);
}
private String incrementNumber(String numbers) {
int number = Integer.parseInt(numbers);
number += 1;
String value = String.format("%04d", number);
return value;
}
}
So I pass the value to setPlate(), get the "next plate" from getIncrementedPlate() and that value is passed again to setPlate() to generate the next plate.
It works. But it takes a lifetime (from AAA0001 to AAB0001 takes 49 seconds!), consumes 100% of all the processors and as I mentioned before, lacks quality.
Could anyone point how to improve it or show me a better improved version?
My current idea to improve the code:
- Change the entity to have 3 chars, each representing each letter. The entity getPlate will concatenate the chars with the numbers when the getPlate is called.
- This "PlateIncrement" class will be changed to receive the entity instead of the String. When I request the "nextPlate()", it will know how to properly increment the chars from the entity.
- I will hold all the possible numbers in-memory. It will be 0,32MB for all the numbers, so it will be ultra cheap.
All suggestions for improvement are welcome!
perl -E 'for $w ("AAA".."ZZZ") { printf "$w%04d\n", $_ for 1..9999 }'
\$\endgroup\$("AAA".."ZZZ").to_a.product(("0001".."9999").to_a).map(&:join)
\$\endgroup\$