My application state is represented by a string of numbers and I'm trying to encode the string so that it is as small as possible (ie. fewest number of characters). An example string would be: 133223333302302040
I realized that most of these strings consist of number pairs containing 0
, 1
, 2
, 3
(4
and 5
also exist but are rare). I decided to replace the most common number pairs with letters, shortening my encoded string by ~50%
I have a function that returns the mapping:
function getValueMap(lettersFirst = false) {
const map = {
'00': 'a',
'01': 'b',
'02': 'c',
'03': 'd',
'10': 'e',
'11': 'f',
'12': 'g',
'13': 'h',
'20': 'i',
'21': 'j',
'22': 'k',
'23': 'l',
'30': 'm',
'31': 'n',
'32': 'o',
'33': 'p'
};
if (lettersFirst) {
return Object.fromEntries(Object.entries(map).map(([k, v]) => [v, k]));
} else {
return map;
}
}
To encode, I iterate through every pair of input numbers, check if it is in the map, and if so, add the letter to the encoded output. For odd length inputs I simply remove the last digit, dont encode it, and simply append the number to the output string untouched:
encode(text) {
const map = getValueMap();
let values;
let suffix = '';
if (text.length % 2 !== 0) {
suffix = text.charAt(text.length - 1);
values = text.slice(0, -1);
} else {
values = text;
}
let encoded = '';
for (let i = 0; i <= text.length - 2; i += 2) {
if (map[values[i] + values[i + 1]]) {
encoded += map[values[i] + values[i + 1]];
} else {
encoded += values[i] + values[i + 1];
}
}
encoded += suffix;
return encoded;
}
To decode, iterate through the string, if its a letter, add the corresponding number pair to the decoded output. If its already a number, simply add the number instead:
decode(encoded) {
const map = getValueMap(true);
let decoded = '';
for (let i = 0; i < encoded.length; i++) {
if (encoded[i].toLowerCase() !== encoded[i].toUpperCase()) {
decoded += map[encoded[i]];
} else {
decoded += encoded[i];
}
}
return decoded;
}
Some example inputs and outputs:
Encode:
13223233202200252044 -> hkopika25i44
Decode:
holppcmi40 -> 133223333302302040
Is there a more straightforward way to do this? My implementation feels unnecessarily obtuse. For example, do I actually need to create a map/reverse map when I could maybe rely on indexing the pair array or alphabet instead? Is there a more elegant way to iterate over pairs of numbers? Or to build up the final encoded/decoded form without appending to a string?