Converting an integer to a 3 character String (base62)

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
3
down vote

favorite
1












I wrote a code to convert an Integer between 1 and 238328 to a unique String, formed from base62 characters (A-Za-z0-9) and of length 3. The String generated can be reconverted to get back the initial Integer.



For example, if the number was 238328 I can convert it to "zzz". I want to be able to use that String "zzz" and get back the number 238328. I have written 2 methods to perform these operations and based on my testing it is working fine.



I am looking for some inputs on making it more readable and possibly more efficient. The conversion consists of 3 nested loops which really does not look right, though I can't get my head around a better way to do this.



class Permutation 

private final String DICTIONARY = new String
"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","U","V","W","X","Y","Z",
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z";

private Map<String, Integer> codes = new HashMap<>();
private Map<Integer, String> numbers = new HashMap<>();

String generateCode(int num) num < 1) return null;

if(numbers.containsKey(num))
return numbers.get(num);


int counter = 0;

for (int i = 0; i < DICTIONARY.length; i++)
for (int j = 0; j < DICTIONARY.length; j++)
for (int k = 0; k < DICTIONARY.length; k++)
String code = DICTIONARY[i] + DICTIONARY[j] + DICTIONARY[k];
counter++;
numbers.put(counter, code);
codes.put(code, counter);
if(counter == num) return code;




return null;


int decode(String code)
if(codes.containsKey(code))
return codes.get(code);


return 0;








share|improve this question





















  • As you noticed, it is base 62. Conversion is a simple matter of 3 multiplications/divisions.
    – vnp
    Mar 20 at 19:56
















up vote
3
down vote

favorite
1












I wrote a code to convert an Integer between 1 and 238328 to a unique String, formed from base62 characters (A-Za-z0-9) and of length 3. The String generated can be reconverted to get back the initial Integer.



For example, if the number was 238328 I can convert it to "zzz". I want to be able to use that String "zzz" and get back the number 238328. I have written 2 methods to perform these operations and based on my testing it is working fine.



I am looking for some inputs on making it more readable and possibly more efficient. The conversion consists of 3 nested loops which really does not look right, though I can't get my head around a better way to do this.



class Permutation 

private final String DICTIONARY = new String
"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","U","V","W","X","Y","Z",
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z";

private Map<String, Integer> codes = new HashMap<>();
private Map<Integer, String> numbers = new HashMap<>();

String generateCode(int num) num < 1) return null;

if(numbers.containsKey(num))
return numbers.get(num);


int counter = 0;

for (int i = 0; i < DICTIONARY.length; i++)
for (int j = 0; j < DICTIONARY.length; j++)
for (int k = 0; k < DICTIONARY.length; k++)
String code = DICTIONARY[i] + DICTIONARY[j] + DICTIONARY[k];
counter++;
numbers.put(counter, code);
codes.put(code, counter);
if(counter == num) return code;




return null;


int decode(String code)
if(codes.containsKey(code))
return codes.get(code);


return 0;








share|improve this question





















  • As you noticed, it is base 62. Conversion is a simple matter of 3 multiplications/divisions.
    – vnp
    Mar 20 at 19:56












up vote
3
down vote

favorite
1









up vote
3
down vote

favorite
1






1





I wrote a code to convert an Integer between 1 and 238328 to a unique String, formed from base62 characters (A-Za-z0-9) and of length 3. The String generated can be reconverted to get back the initial Integer.



For example, if the number was 238328 I can convert it to "zzz". I want to be able to use that String "zzz" and get back the number 238328. I have written 2 methods to perform these operations and based on my testing it is working fine.



I am looking for some inputs on making it more readable and possibly more efficient. The conversion consists of 3 nested loops which really does not look right, though I can't get my head around a better way to do this.



class Permutation 

private final String DICTIONARY = new String
"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","U","V","W","X","Y","Z",
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z";

private Map<String, Integer> codes = new HashMap<>();
private Map<Integer, String> numbers = new HashMap<>();

String generateCode(int num) num < 1) return null;

if(numbers.containsKey(num))
return numbers.get(num);


int counter = 0;

for (int i = 0; i < DICTIONARY.length; i++)
for (int j = 0; j < DICTIONARY.length; j++)
for (int k = 0; k < DICTIONARY.length; k++)
String code = DICTIONARY[i] + DICTIONARY[j] + DICTIONARY[k];
counter++;
numbers.put(counter, code);
codes.put(code, counter);
if(counter == num) return code;




return null;


int decode(String code)
if(codes.containsKey(code))
return codes.get(code);


return 0;








share|improve this question













I wrote a code to convert an Integer between 1 and 238328 to a unique String, formed from base62 characters (A-Za-z0-9) and of length 3. The String generated can be reconverted to get back the initial Integer.



For example, if the number was 238328 I can convert it to "zzz". I want to be able to use that String "zzz" and get back the number 238328. I have written 2 methods to perform these operations and based on my testing it is working fine.



I am looking for some inputs on making it more readable and possibly more efficient. The conversion consists of 3 nested loops which really does not look right, though I can't get my head around a better way to do this.



class Permutation 

private final String DICTIONARY = new String
"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","U","V","W","X","Y","Z",
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z";

private Map<String, Integer> codes = new HashMap<>();
private Map<Integer, String> numbers = new HashMap<>();

String generateCode(int num) num < 1) return null;

if(numbers.containsKey(num))
return numbers.get(num);


int counter = 0;

for (int i = 0; i < DICTIONARY.length; i++)
for (int j = 0; j < DICTIONARY.length; j++)
for (int k = 0; k < DICTIONARY.length; k++)
String code = DICTIONARY[i] + DICTIONARY[j] + DICTIONARY[k];
counter++;
numbers.put(counter, code);
codes.put(code, counter);
if(counter == num) return code;




return null;


int decode(String code)
if(codes.containsKey(code))
return codes.get(code);


return 0;










share|improve this question












share|improve this question




share|improve this question








edited Mar 20 at 23:51









Phrancis

14.6k645137




14.6k645137









asked Mar 20 at 19:35









karvai

184




184











  • As you noticed, it is base 62. Conversion is a simple matter of 3 multiplications/divisions.
    – vnp
    Mar 20 at 19:56
















  • As you noticed, it is base 62. Conversion is a simple matter of 3 multiplications/divisions.
    – vnp
    Mar 20 at 19:56















As you noticed, it is base 62. Conversion is a simple matter of 3 multiplications/divisions.
– vnp
Mar 20 at 19:56




As you noticed, it is base 62. Conversion is a simple matter of 3 multiplications/divisions.
– vnp
Mar 20 at 19:56










1 Answer
1






active

oldest

votes

















up vote
2
down vote



accepted










Your problem definition is .... odd. your code, will, for the input value 1 generate the output 000. Is that what you really want? Why do you need to 1-index the value set instead of 0-index it?



Further, your code caches all values up-to-and-including the input value in a HashMap. This can become quite large.... for the full dataset you're looking at about a quarter-million values where each is about 128 bytes of memory (a String, an Integer, and a Map.Entry plus some other overheads), or about 70 megabytes of data.



Your DICTIONARY should be an array of chars, not an array of String.



The maxNumber should be a static constant too.



Finally, you return a null value for an invalid input. That's very unconventional, you should throw an IllegalArgumentException instead.



As mentioned in a comment, you can "easily" solve your problem with a few "simple" operations.



private static final char DIGITS = ("0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz").toCharArray();
private static final int BASE = DIGITS.length;
private static final int MAX_NUMBER = BASE * BASE * BASE;

public static String generateCode(int num)


Note that I compute each digit separately (in to ac, bc, and cc) and then return the combination as a string.



Further, when running the code, I discovered that you are off on your zzz assertion .... the max value you propose for zzz is wrong, what you have is yyy. - I discovered I had a text transpose of zy instead of yz in my constant.



See the code running on ideone: https://ideone.com/EZqXlJ



For the inputs supplied in the tests I get the values:



Value 0 Error Illegal input value: 0
Value 1: 000
Value 2: 001
Value 62: 00z
Value 63: 010
Value 1000: 0G7
Value 238328: zzz
Value 238329 Error Illegal input value: 238329





share|improve this answer























  • Maybe specifying DICTIONARY with a long literal isn't the best of ideas - I doubt doing same for MaxNumber without sanity check against DICTIONARY is. Without specification, I'd use "little-endian" "digit" strings.
    – greybeard
    Mar 20 at 22:12










  • @greybeard - not sure I follow all you are suggesting, but you've made me realize that the naming conventions are off, and using an array of "digits" is better than a Dictionary.charAt() concept. Editing my answer.
    – rolfl♦
    Mar 20 at 23:27










  • @karvai - I subtract the number by 1 because your specification demands it. What does your code give you for generateCode(1)... it gives 000 ... right? That's why I subtract 1, and that was the first issue I noted in my answer.
    – rolfl♦
    Mar 20 at 23:30










Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f190062%2fconverting-an-integer-to-a-3-character-string-base62%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
2
down vote



accepted










Your problem definition is .... odd. your code, will, for the input value 1 generate the output 000. Is that what you really want? Why do you need to 1-index the value set instead of 0-index it?



Further, your code caches all values up-to-and-including the input value in a HashMap. This can become quite large.... for the full dataset you're looking at about a quarter-million values where each is about 128 bytes of memory (a String, an Integer, and a Map.Entry plus some other overheads), or about 70 megabytes of data.



Your DICTIONARY should be an array of chars, not an array of String.



The maxNumber should be a static constant too.



Finally, you return a null value for an invalid input. That's very unconventional, you should throw an IllegalArgumentException instead.



As mentioned in a comment, you can "easily" solve your problem with a few "simple" operations.



private static final char DIGITS = ("0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz").toCharArray();
private static final int BASE = DIGITS.length;
private static final int MAX_NUMBER = BASE * BASE * BASE;

public static String generateCode(int num)


Note that I compute each digit separately (in to ac, bc, and cc) and then return the combination as a string.



Further, when running the code, I discovered that you are off on your zzz assertion .... the max value you propose for zzz is wrong, what you have is yyy. - I discovered I had a text transpose of zy instead of yz in my constant.



See the code running on ideone: https://ideone.com/EZqXlJ



For the inputs supplied in the tests I get the values:



Value 0 Error Illegal input value: 0
Value 1: 000
Value 2: 001
Value 62: 00z
Value 63: 010
Value 1000: 0G7
Value 238328: zzz
Value 238329 Error Illegal input value: 238329





share|improve this answer























  • Maybe specifying DICTIONARY with a long literal isn't the best of ideas - I doubt doing same for MaxNumber without sanity check against DICTIONARY is. Without specification, I'd use "little-endian" "digit" strings.
    – greybeard
    Mar 20 at 22:12










  • @greybeard - not sure I follow all you are suggesting, but you've made me realize that the naming conventions are off, and using an array of "digits" is better than a Dictionary.charAt() concept. Editing my answer.
    – rolfl♦
    Mar 20 at 23:27










  • @karvai - I subtract the number by 1 because your specification demands it. What does your code give you for generateCode(1)... it gives 000 ... right? That's why I subtract 1, and that was the first issue I noted in my answer.
    – rolfl♦
    Mar 20 at 23:30














up vote
2
down vote



accepted










Your problem definition is .... odd. your code, will, for the input value 1 generate the output 000. Is that what you really want? Why do you need to 1-index the value set instead of 0-index it?



Further, your code caches all values up-to-and-including the input value in a HashMap. This can become quite large.... for the full dataset you're looking at about a quarter-million values where each is about 128 bytes of memory (a String, an Integer, and a Map.Entry plus some other overheads), or about 70 megabytes of data.



Your DICTIONARY should be an array of chars, not an array of String.



The maxNumber should be a static constant too.



Finally, you return a null value for an invalid input. That's very unconventional, you should throw an IllegalArgumentException instead.



As mentioned in a comment, you can "easily" solve your problem with a few "simple" operations.



private static final char DIGITS = ("0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz").toCharArray();
private static final int BASE = DIGITS.length;
private static final int MAX_NUMBER = BASE * BASE * BASE;

public static String generateCode(int num)


Note that I compute each digit separately (in to ac, bc, and cc) and then return the combination as a string.



Further, when running the code, I discovered that you are off on your zzz assertion .... the max value you propose for zzz is wrong, what you have is yyy. - I discovered I had a text transpose of zy instead of yz in my constant.



See the code running on ideone: https://ideone.com/EZqXlJ



For the inputs supplied in the tests I get the values:



Value 0 Error Illegal input value: 0
Value 1: 000
Value 2: 001
Value 62: 00z
Value 63: 010
Value 1000: 0G7
Value 238328: zzz
Value 238329 Error Illegal input value: 238329





share|improve this answer























  • Maybe specifying DICTIONARY with a long literal isn't the best of ideas - I doubt doing same for MaxNumber without sanity check against DICTIONARY is. Without specification, I'd use "little-endian" "digit" strings.
    – greybeard
    Mar 20 at 22:12










  • @greybeard - not sure I follow all you are suggesting, but you've made me realize that the naming conventions are off, and using an array of "digits" is better than a Dictionary.charAt() concept. Editing my answer.
    – rolfl♦
    Mar 20 at 23:27










  • @karvai - I subtract the number by 1 because your specification demands it. What does your code give you for generateCode(1)... it gives 000 ... right? That's why I subtract 1, and that was the first issue I noted in my answer.
    – rolfl♦
    Mar 20 at 23:30












up vote
2
down vote



accepted







up vote
2
down vote



accepted






Your problem definition is .... odd. your code, will, for the input value 1 generate the output 000. Is that what you really want? Why do you need to 1-index the value set instead of 0-index it?



Further, your code caches all values up-to-and-including the input value in a HashMap. This can become quite large.... for the full dataset you're looking at about a quarter-million values where each is about 128 bytes of memory (a String, an Integer, and a Map.Entry plus some other overheads), or about 70 megabytes of data.



Your DICTIONARY should be an array of chars, not an array of String.



The maxNumber should be a static constant too.



Finally, you return a null value for an invalid input. That's very unconventional, you should throw an IllegalArgumentException instead.



As mentioned in a comment, you can "easily" solve your problem with a few "simple" operations.



private static final char DIGITS = ("0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz").toCharArray();
private static final int BASE = DIGITS.length;
private static final int MAX_NUMBER = BASE * BASE * BASE;

public static String generateCode(int num)


Note that I compute each digit separately (in to ac, bc, and cc) and then return the combination as a string.



Further, when running the code, I discovered that you are off on your zzz assertion .... the max value you propose for zzz is wrong, what you have is yyy. - I discovered I had a text transpose of zy instead of yz in my constant.



See the code running on ideone: https://ideone.com/EZqXlJ



For the inputs supplied in the tests I get the values:



Value 0 Error Illegal input value: 0
Value 1: 000
Value 2: 001
Value 62: 00z
Value 63: 010
Value 1000: 0G7
Value 238328: zzz
Value 238329 Error Illegal input value: 238329





share|improve this answer















Your problem definition is .... odd. your code, will, for the input value 1 generate the output 000. Is that what you really want? Why do you need to 1-index the value set instead of 0-index it?



Further, your code caches all values up-to-and-including the input value in a HashMap. This can become quite large.... for the full dataset you're looking at about a quarter-million values where each is about 128 bytes of memory (a String, an Integer, and a Map.Entry plus some other overheads), or about 70 megabytes of data.



Your DICTIONARY should be an array of chars, not an array of String.



The maxNumber should be a static constant too.



Finally, you return a null value for an invalid input. That's very unconventional, you should throw an IllegalArgumentException instead.



As mentioned in a comment, you can "easily" solve your problem with a few "simple" operations.



private static final char DIGITS = ("0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz").toCharArray();
private static final int BASE = DIGITS.length;
private static final int MAX_NUMBER = BASE * BASE * BASE;

public static String generateCode(int num)


Note that I compute each digit separately (in to ac, bc, and cc) and then return the combination as a string.



Further, when running the code, I discovered that you are off on your zzz assertion .... the max value you propose for zzz is wrong, what you have is yyy. - I discovered I had a text transpose of zy instead of yz in my constant.



See the code running on ideone: https://ideone.com/EZqXlJ



For the inputs supplied in the tests I get the values:



Value 0 Error Illegal input value: 0
Value 1: 000
Value 2: 001
Value 62: 00z
Value 63: 010
Value 1000: 0G7
Value 238328: zzz
Value 238329 Error Illegal input value: 238329






share|improve this answer















share|improve this answer



share|improve this answer








edited Mar 20 at 23:29


























answered Mar 20 at 20:54









rolfl♦

90.2k13186390




90.2k13186390











  • Maybe specifying DICTIONARY with a long literal isn't the best of ideas - I doubt doing same for MaxNumber without sanity check against DICTIONARY is. Without specification, I'd use "little-endian" "digit" strings.
    – greybeard
    Mar 20 at 22:12










  • @greybeard - not sure I follow all you are suggesting, but you've made me realize that the naming conventions are off, and using an array of "digits" is better than a Dictionary.charAt() concept. Editing my answer.
    – rolfl♦
    Mar 20 at 23:27










  • @karvai - I subtract the number by 1 because your specification demands it. What does your code give you for generateCode(1)... it gives 000 ... right? That's why I subtract 1, and that was the first issue I noted in my answer.
    – rolfl♦
    Mar 20 at 23:30
















  • Maybe specifying DICTIONARY with a long literal isn't the best of ideas - I doubt doing same for MaxNumber without sanity check against DICTIONARY is. Without specification, I'd use "little-endian" "digit" strings.
    – greybeard
    Mar 20 at 22:12










  • @greybeard - not sure I follow all you are suggesting, but you've made me realize that the naming conventions are off, and using an array of "digits" is better than a Dictionary.charAt() concept. Editing my answer.
    – rolfl♦
    Mar 20 at 23:27










  • @karvai - I subtract the number by 1 because your specification demands it. What does your code give you for generateCode(1)... it gives 000 ... right? That's why I subtract 1, and that was the first issue I noted in my answer.
    – rolfl♦
    Mar 20 at 23:30















Maybe specifying DICTIONARY with a long literal isn't the best of ideas - I doubt doing same for MaxNumber without sanity check against DICTIONARY is. Without specification, I'd use "little-endian" "digit" strings.
– greybeard
Mar 20 at 22:12




Maybe specifying DICTIONARY with a long literal isn't the best of ideas - I doubt doing same for MaxNumber without sanity check against DICTIONARY is. Without specification, I'd use "little-endian" "digit" strings.
– greybeard
Mar 20 at 22:12












@greybeard - not sure I follow all you are suggesting, but you've made me realize that the naming conventions are off, and using an array of "digits" is better than a Dictionary.charAt() concept. Editing my answer.
– rolfl♦
Mar 20 at 23:27




@greybeard - not sure I follow all you are suggesting, but you've made me realize that the naming conventions are off, and using an array of "digits" is better than a Dictionary.charAt() concept. Editing my answer.
– rolfl♦
Mar 20 at 23:27












@karvai - I subtract the number by 1 because your specification demands it. What does your code give you for generateCode(1)... it gives 000 ... right? That's why I subtract 1, and that was the first issue I noted in my answer.
– rolfl♦
Mar 20 at 23:30




@karvai - I subtract the number by 1 because your specification demands it. What does your code give you for generateCode(1)... it gives 000 ... right? That's why I subtract 1, and that was the first issue I noted in my answer.
– rolfl♦
Mar 20 at 23:30












 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f190062%2fconverting-an-integer-to-a-3-character-string-base62%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Greedy Best First Search implementation in Rust

Function to Return a JSON Like Objects Using VBA Collections and Arrays

C++11 CLH Lock Implementation