Given a string and the characters used to encode it, you need to compress the string by only using as many bits as each character needs. You will return the character codes for each character needed to create a compressed string.
For example, given the string "the fox"
and the encoder characters " abcdefghijklmnopqrstuvwxyz"
, the output should be [170, 76, 19, 195, 32]
.
How, though?
First, you need to map each encoder character to some bits. If we have the encoder characters abc
, then we can map the characters to bits, by mapping the character to the position of the character in binary, like this:
a => 01
b => 10
c => 11
With 13579
, we would map it like this:
1 => 001
3 => 010
5 => 011
7 => 100
9 => 101
Note that we pad zeros at the beginning as many as necessary.
Next, we would go through the string, and for each character, we would get the corresponding bits for that character. Then join all the bits together, and then convert to chunks of 8 to get the bytes. If the last byte is not 8 bits long, add zeros at the end till it is 8 bits long. Lastly, convert each byte to its decimal representation.
Test cases
String: "the fox", encoder characters: " abcdefghijklmnopqrstuvwxyz" => [170, 76, 19, 195, 32]
String: "971428563", encoder characters: "123456789" => [151, 20, 40, 86, 48]
String: "the quick brown fox jumps over the lazy dog", encoder characters: " abcdefghijklmnopqrstuvwxyz" => [170, 76, 25, 89, 68, 96, 71, 56, 97, 225, 60, 50, 21, 217, 209, 160, 97, 115, 76, 53, 73, 130, 209, 111, 65, 44, 16]
String: "abc", encoder characters: "abc" => [108]
String: "aaaaaaaa", encoder characters: "a" => [255]
String: "aaaabbbb", encoder characters: "ab" => [85, 170]
Rules
- Inputs can be a string, list, or even list of character codes. It doesn't matter, I/O is very flexible for this challenge.
- Input will always be valid, e.g. the string will never include characters not in the encoder characters, etc.
- Encoder characters will always contain **less than 256 characters.
- Neither input will ever be empty.
- This is code-golf, so the shortest answer in bytes for each language wins.
- Standard I/O rules apply.
- Default loopholes are forbidden.
Reference implementation in JavaScript
function encode(str, encoderChars) {
const maxBitCount = Math.ceil(Math.log2(encoderChars.length + 1));
const charToBit = Object.fromEntries(encoderChars.map((c, i) => [c, (i + 1).toString(2).padStart(maxBitCount, "0")]));
const bits = [...str].map((c) => charToBit[c]).join("");
const bytes = bits.match(/.{1,8}/g) || [];
return bytes.map((x) => parseInt(x.padEnd(8, '0'), 2));
}
"aaaaaaaa","a"
and"aaaaaaaa","ab"
to check thatmaxBitCount
is correctly calculated \$\endgroup\$"aaaaaaaa","ab" -> [85, 85]
should be added. \$\endgroup\$