- Link to this page:
https://bit.ly/vid5B62P2Rick
#java #functionalprogramming #scala #base62
Porting Base62Encoder/Decoder to Scala from Java. Then from Scala to more idiomatic/functional Scala.
Base62Encoder is written using FP and non FP in Go Lang, Java, Scala, Kotlin, JavaScript, TypeScript, Clojure, Rust and Python to demonstrate and discuss FP support in different languages.
These are show notes for this video - Porting Base62Encoder/Decoder from Java to functional Scala
- First Video in Base62 language series 3rd Vlog video Show Notes
- Second Video in Base62 language (Java) series 4th Vlog video Show Notes
- Third Video in Base62 language (Scala) series 5th Vlog video Show Notes
- Fourth Video in Base62 language (Clojure) series 6th Vlog video Show notes
- Fifth Video in Base62 language (Python) series 7th Vlog video Show notes
- Sixth Video in Base62 language (JavaScript/TypeScript) series 8th Vlog video Show notes
- Seventh Video in Base62 language (Rust) series 9th Vlog video Show notes
- Eighth Video in Base62 language (Go Lang) series 10th Vlog video Show notes
Java | Scala |
---|---|
public static void main(String[] args) {
final long id = 12345678910L;
final String strId = convertToEncodedString(id);
final long newId = convertToLong(strId);
System.out.printf("%d %s %d\n", id, strId, newId);
final String longURL = "https://www.somewebiste.com/dp/...";
final long urlId = Math.abs(longURL.hashCode());
final String shortHandle = convertToEncodedString(urlId);
System.out.printf("%d %s %d\n", urlId,
shortHandle, convertToLong(shortHandle));
} |
def main(args: Array[String]): Unit = {
val id = 12345678910L
val strId = convertToEncodedString(id)
val newId = convertToLong(strId)
printf("%d %s %d\n", id, strId, newId)
val longURL = "https://www.somewebiste.com/dp/..."
val urlId = Math.abs(longURL.hashCode)
val shortHandle = convertToEncodedString(urlId)
printf("%d %s %d\n", urlId,
shortHandle, convertToLong(shortHandle))
} |
Java | Scala |
---|---|
public static String convertToEncodedString(final long id) {
final StringBuilder builder = new StringBuilder();
int placeHolder = findStartBucket(id);
long bucketValue;
long acc = id;
int digitIndex;
while (placeHolder > 1) {
//bucketValue = buckets[index];
bucketValue = powDigitsBase(placeHolder);
digitIndex = (int) (acc / bucketValue);
acc = acc - (bucketValue * digitIndex);
appendSafe(builder, digitIndex);
placeHolder--;
}
//bucketValue = buckets[1];
bucketValue = powDigitsBase(1);
digitIndex = (int) (acc / bucketValue);
acc = acc - (bucketValue * digitIndex);
appendSafe(builder, digitIndex);
//Put the remainder in the ones column
digitIndex = (int) (acc % bucketValue);
builder.append(DIGITS[digitIndex]);
return builder.toString();
} |
def convertToEncodedString(id: Long): String = {
val builder = new StringBuilder
var placeHolder = findStartBucket(id)
var bucketValue = 0L
var acc = id
var digitIndex = 0
while (placeHolder > 1) {
//bucketValue = buckets[index];
bucketValue = powDigitsBase(placeHolder)
digitIndex = (acc / bucketValue).toInt
acc = acc - (bucketValue * digitIndex)
appendSafe(builder, digitIndex)
placeHolder -= 1
}
//bucketValue = buckets[1];
bucketValue = powDigitsBase(1)
digitIndex = (acc / bucketValue).toInt
acc = acc - (bucketValue * digitIndex)
appendSafe(builder, digitIndex)
//Put the remainder in the ones column
digitIndex = (acc % bucketValue).toInt
builder.append(DIGITS(digitIndex))
builder.toString
} |
Java | Scala |
---|---|
private static int findStartBucket(long value) {
for (int i = 0; i < 15; i++) {
if (value < powDigitsBase(i)) {
return i-1;
}
}
return 0;
} |
private def findStartBucket(value: Long): Int = {
for (i <- 0 until 15) {
if (value < powDigitsBase(i)) return i - 1
}
0
} |
Java | Scala |
---|---|
private static long powDigitsBase( final long exponent) {
return doPow(exponent, DIGITS.length);
}
private static long doPow( final long exponent, final long base) {
long result = 1;
long exp = exponent;
while (exp != 0) {
result *= base;
--exp;
}
return result;
} |
private def powDigitsBase(exponent: Long) =
doPow(exponent, DIGITS.length.toLong)
private def doPow(exponent: Long, base: Long) = {
var result = 1L
var exp = exponent
while (exp != 0) {
result = result * base
exp -= 1
}
result
} |
Java | Scala |
---|---|
private static void appendSafe(StringBuilder builder, int digitIndex) {
if (digitIndex != 0) {
builder.append(DIGITS[digitIndex]);
} else {
if (builder.length() > 0) {
builder.append(DIGITS[digitIndex]);
}
}
} |
private def appendSafe(builder: StringBuilder, digitIndex: Int): Unit = {
if (digitIndex != 0) builder.append(DIGITS(digitIndex))
else if (builder.nonEmpty) builder.append(DIGITS(digitIndex))
} |
Java | Scala |
---|---|
public static long convertToLong(String strId) {
return convertToLong(strId.toCharArray());
}
private static long convertToLong(char[] chars) {
long acc = 0;
int position = 0;
for (int index = chars.length - 1; index > -1; index--) {
char c = chars[index];
long value = computeValue(c, position);
acc += value;
position++;
}
return acc;
} |
def convertToLong(strId: String): Long =
convertToLong(strId.toCharArray)
private def convertToLong(chars: Array[Char]) = {
var acc = 0L
var position = 0
for (index <- chars.length - 1 until -1 by -1) {
val c = chars(index)
val value = computeValue(c, position)
acc = acc + value
position += 1
}
acc
}
|
Java | Scala |
---|---|
private static long computeValue(char c, int position) {
final int digitIndex = findIndexOfDigitInTable(c);
final long multiplier = powDigitsBase(position);
//final long multiplier = buckets[position];
return digitIndex * multiplier;
} |
private def computeValue(c: Char, position: Int) = {
val digitIndex = findIndexOfDigitInTable(c)
val multiplier = powDigitsBase(position)
digitIndex * multiplier
}
|
Java | Scala |
---|---|
private static int findIndexOfDigitInTable(char c) {
for (int i = 0; i < DIGITS.length; i++) {
char digit = DIGITS[i];
if (c == digit) {
return i;
}
}
throw new IllegalStateException("Unknown char #" + c + "#");
} |
private def findIndexOfDigitInTable(c: Char): Int = {
for (i <- 0 until DIGITS.length) {
val digit = DIGITS(i)
if (c == digit) return i
}
throw new IllegalStateException("Unknown char #" + c + "#")
} |
Functional Scala | Scala |
---|---|
def main(args: Array[String]): Unit = {
val id = 12345678910L
val strId = convertToEncodedString(id)
val newId = convertToLong(strId)
println(s"$id $strId $newId")
val longURL = "https://www.somewebiste.com/dp/..."
val urlId = Math.abs(longURL.hashCode)
val shortHandle = convertToEncodedString(urlId)
println(s"$urlId $shortHandle ${convertToLong(shortHandle)}")
} |
def main(args: Array[String]): Unit = {
val id = 12345678910L
val strId = convertToEncodedString(id)
val newId = convertToLong(strId)
printf("%d %s %d\n", id, strId, newId)
val longURL = "https://www.somewebiste.com/dp/..."
val urlId = Math.abs(longURL.hashCode)
val shortHandle = convertToEncodedString(urlId)
printf("%d %s %d\n", urlId,
shortHandle, convertToLong(shortHandle))
} |
Functional Scala | Scala |
---|---|
def convertToEncodedString(id: Long): String = {
val builder: List[String] = List()
val placeHolder = findStartBucket(id)
val results = accumulateDigits(placeHolder, id, builder)
val bucketValue = powDigitsBase(1)
val digitIndex: Int = (results._2 / bucketValue).toInt
val acc = results._2 - (bucketValue * digitIndex)
val newBuilder: List[String] = appendSafeToList(results._3, digitIndex)
//Put the remainder in the ones column
val place1DigitIndex = (acc % bucketValue).toInt
val finalBuilder = newBuilder ++ List(DIGITS(place1DigitIndex).toString)
finalBuilder.mkString("")
}
private def accumulateDigits(placeHolder: Int, acc: Long,
builder: List[String]): (Int, Long, List[String]) = {
if (!(placeHolder > 1)) {
return (placeHolder, acc, builder)
}
val bucketValue = powDigitsBase(placeHolder)
val digitIndex = (acc / bucketValue).toInt
accumulateDigits(placeHolder - 1, acc - (bucketValue * digitIndex),
appendSafeToList(builder, digitIndex))
} |
def convertToEncodedString(id: Long): String = {
val builder = new StringBuilder
var placeHolder = findStartBucket(id)
var bucketValue = 0L
var acc = id
var digitIndex = 0
while (placeHolder > 1) {
//bucketValue = buckets[index];
bucketValue = powDigitsBase(placeHolder)
digitIndex = (acc / bucketValue).toInt
acc = acc - (bucketValue * digitIndex)
appendSafe(builder, digitIndex)
placeHolder -= 1
}
//bucketValue = buckets[1];
bucketValue = powDigitsBase(1)
digitIndex = (acc / bucketValue).toInt
acc = acc - (bucketValue * digitIndex)
appendSafe(builder, digitIndex)
//Put the remainder in the ones column
digitIndex = (acc % bucketValue).toInt
builder.append(DIGITS(digitIndex))
builder.toString
} |
Functional Scala | Scala |
---|---|
private def findStartBucket(value: Long): Int = {
val i = Range(0, 15, 1).find(i => value < powDigitsBase(i.toLong))
i.getOrElse(0)
} |
private def findStartBucket(value: Long): Int = {
for (i <- 0 until 15) {
if (value < powDigitsBase(i)) return i - 1
}
0
} |
Functional Scala | Scala |
---|---|
private def powDigitsBase(exponent: Long): Long =
doPow(exponent, DIGITS.length)
private def doPow(exponent: Long, base: Int): Long = {
if (exponent == 0) return 1
doPow(exponent - 1, base) * base
}
|
private def powDigitsBase(exponent: Long) =
doPow(exponent, DIGITS.length.toLong)
private def doPow(exponent: Long, base: Long) = {
var result = 1L
var exp = exponent
while (exp != 0) {
result = result * base
exp -= 1
}
result
} |
Functional Scala | Scala |
---|---|
private def appendSafeToList(builder: List[String], digitIndex: Int): List[String] = {
if (digitIndex != 0) builder ++ List((DIGITS(digitIndex)).toString)
else if (builder.nonEmpty) builder ++ List((DIGITS(digitIndex)).toString)
else builder
} |
private def appendSafe(builder: StringBuilder, digitIndex: Int): Unit = {
if (digitIndex != 0) builder.append(DIGITS(digitIndex))
else if (builder.nonEmpty) builder.append(DIGITS(digitIndex))
} |
Functional Scala | Scala |
---|---|
def convertToLong(strId: String): Long =
doConvertToLong(strId.toCharArray)
private def doConvertToLong(chars: Array[Char]): Long = {
val (acc, _) = chars.reverse.foldLeft(0L, 0) { (pos, ch) =>
val (acc, position) = pos
val value = computeValue(ch, position)
(acc + value, position + 1)
}
acc
} |
def convertToLong(strId: String): Long =
convertToLong(strId.toCharArray)
private def convertToLong(chars: Array[Char]) = {
var acc = 0L
var position = 0
for (index <- chars.length - 1 until -1 by -1) {
val c = chars(index)
val value = computeValue(c, position)
acc = acc + value
position += 1
}
acc
}
|
Functional Scala | Scala |
---|---|
private def computeValue(c: Char, position: Int) = {
val digitIndex = findIndexOfDigitInTable(c)
val multiplier = powDigitsBase(position)
digitIndex * multiplier
} |
private def computeValue(c: Char, position: Int) = {
val digitIndex = findIndexOfDigitInTable(c)
val multiplier = powDigitsBase(position)
digitIndex * multiplier
}
|
Functional Scala | Scala |
---|---|
private def findIndexOfDigitInTable(c: Char): Int = {
val i = DIGITS.indexOf(c);
if (i == -1) {
throw new IllegalStateException("Unknown char #" + c + "#")
}
i
} |
private def findIndexOfDigitInTable(c: Char): Int = {
for (i <- 0 until DIGITS.length) {
val digit = DIGITS(i)
if (c == digit) return i
}
throw new IllegalStateException("Unknown char #" + c + "#")
} |
- How a URL Shortening Application Works
- Designing the Shortening URL system like Bit.ly, loading 6 billion clicks a month
- Rick's YouTube Channel
- Bit.ly Link to last show notes page
- Where Rick works
- Link to this page
- First Video in Base62 language series 3rd Vlog video
- Second Video in Base62 language series 3rd Vlog video
package main.normal;
public class Base62Encoder {
public static void main(String[] args) {
final long id = 12345678910L;
final String strId = convertToEncodedString(id);
final long newId = convertToLong(strId);
System.out.printf("%d %s %d\n", id, strId, newId);
final String longURL = "https://www.somewebiste.com/dp/0201616165/?_encoding=UTF8&pd_rd_w=vwEcs&content-id=amzn1.sym.8cf3b8ef-6a74-45dc-9f0d-6409eb523603&pf_rd_p=8cf3b8ef-6a74-45dc-9f0d-6409eb523603&pf_rd_r=BQ0KD40K57XG761DBNBA&pd_rd_wg=DtkHk&pd_rd_r=f94b60b7-9080-4065-b77f-6377ec854d17&ref_=pd_gw_ci_mcx_mi";
final long urlId = Math.abs(longURL.hashCode()); //or save URL in DB and get ID from DB row.
final String shortHandle = convertToEncodedString(urlId);
System.out.printf("%d %s %d\n", urlId, shortHandle, convertToLong(shortHandle));
}
private static final char[] DIGITS = {
//0 1 2 3 4 5 6 7 8 9
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
//10 11 12 13 14 15 16 17 18 19 20 21
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
//22 23 24 25 26 27 28 29 30 31 32 33 34 35
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
// 36 37 38 39 40 41 42 43 44 45 46 47
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', //Easy to add more characters if not using lookup tables.
// 48 49 50 51 52 53 54 55 56 57 58 59 60 61 // 62 63, 64
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', // '*', '@', '$'
};
public static long convertToLong(String strId) {
return convertToLong(strId.toCharArray());
}
public static String convertToEncodedString(final long id) {
final StringBuilder builder = new StringBuilder();
int placeHolder = findStartBucket(id);
long bucketValue;
long acc = id;
int digitIndex;
while (placeHolder > 1) {
//bucketValue = buckets[index];
bucketValue = powDigitsBase(placeHolder);
digitIndex = (int) (acc / bucketValue);
acc = acc - (bucketValue * digitIndex);
appendSafe(builder, digitIndex);
placeHolder--;
}
//bucketValue = buckets[1];
bucketValue = powDigitsBase(1);
digitIndex = (int) (acc / bucketValue);
acc = acc - (bucketValue * digitIndex);
appendSafe(builder, digitIndex);
//Put the remainder in the ones column
digitIndex = (int) (acc % bucketValue);
builder.append(DIGITS[digitIndex]);
return builder.toString();
}
private static long convertToLong(char[] chars) {
long acc = 0;
int position = 0;
for (int index = chars.length - 1; index > -1; index--) {
char c = chars[index];
long value = computeValue(c, position);
acc += value;
position++;
}
return acc;
}
private static int findIndexOfDigitInTable(char c) {
for (int i = 0; i < DIGITS.length; i++) {
char digit = DIGITS[i];
if (c == digit) {
return i;
}
}
throw new IllegalStateException("Unknown char #" + c + "#");
}
private static long computeValue(char c, int position) {
final int digitIndex = findIndexOfDigitInTable(c);
final long multiplier = powDigitsBase(position);
//final long multiplier = buckets[position];
return digitIndex * multiplier;
}
private static void appendSafe(StringBuilder builder, int digitIndex) {
if (digitIndex != 0) {
builder.append(DIGITS[digitIndex]);
} else {
if (builder.length() > 0) {
builder.append(DIGITS[digitIndex]);
}
}
}
private static long powDigitsBase( final long exponent) {
return doPow(exponent, DIGITS.length);
}
private static long doPow( final long exponent, final long base) {
long result = 1;
long exp = exponent;
while (exp != 0) {
result *= base;
--exp;
}
return result;
}
private static int findStartBucket(long value) {
for (int i = 0; i < 15; i++) {
if (value < powDigitsBase(i)) {
return i-1;
}
}
return 0;
}
}