Created
November 23, 2021 21:33
-
-
Save jaymody/82f0bf12a9a5efaa2282dfe429db9bed to your computer and use it in GitHub Desktop.
Recursive, functional re-implementation of iterable functions (map, reduce, groupBy, etc ...) in Scala.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class MyList[A](l: Seq[A]) { | |
def filter(f: A => Boolean): Seq[A] = l match { | |
case Nil => l | |
case x :: xs if !f(x) => xs.filter(f) | |
case x :: xs if f(x) => x +: xs.filter(f) | |
} | |
def map[B](f: A => B): Seq[B] = l match { | |
case Nil => Nil | |
case x :: xs => f(x) +: xs.map(f) | |
} | |
def groupBy[K](f: A => K): Map[K, Seq[A]] = { | |
def gby(l: Seq[A], m: Map[K, Seq[A]])(implicit f: A => K): Map[K, Seq[A]] = | |
l match { | |
case Nil => m | |
case x :: xs if m.contains(f(x)) => | |
gby(xs, m + (f(x) -> (m(f(x)) :+ x))) | |
case x :: xs if !m.contains(f(x)) => gby(xs, m + (f(x) -> Seq(x))) | |
} | |
gby(l, Map())(f) | |
} | |
def foldLeft[B](z: B)(f: (B, A) => B): B = l match { | |
case Nil => z | |
case x :: xs => xs.foldLeft(f(z, x))(f) | |
} | |
def reduce(f: (A, A) => A): A = l match { | |
case Nil => throw new IllegalArgumentException("List must not be empty") | |
case x :: xs => xs.foldLeft(x)(f) | |
} | |
def forall(p: A => Boolean): Boolean = l match { | |
case Nil => true | |
case x :: xs => p(x) && xs.forall(p) | |
} | |
def foreach(f: A => Unit): Unit = l match { | |
case x :: xs => { f(x); xs.foreach(f) } | |
} | |
def count(p: A => Boolean): Int = l match { | |
case Nil => 0 | |
case x :: xs => xs.count(p) + { if (p(x)) 1 else 0 } | |
} | |
def partition(p: A => Boolean): (Seq[A], Seq[A]) = { | |
val part = l.groupBy(p) | |
(part(true), part(false)) | |
} | |
// TODO: def flatten | |
// TODO: def fold | |
// TODO: def foldRight | |
// TODO: def corresponds | |
// TODO: def indexOf | |
// TODO: def intersect | |
// TODO: def diff | |
// TODO: def distinct | |
// TODO: def drop | |
// TODO: def dropRight | |
// TODO: def combinations | |
// TODO: def collect | |
// TODO: def flatMap | |
// TODO: def permutations | |
// TODO: def union | |
} | |
object Collections { | |
def test[A](a: A, b: A): Unit = { | |
println(a == b) | |
println(a) | |
println(b) | |
println() | |
} | |
def main(args: Array[String]): Unit = { | |
val list = (1 to 10).toList | |
val myList = MyList(list) | |
println("--- test map ---") | |
val f1 = (x: Int) => x * 2 | |
test(myList.map(f1), list.map(f1)) | |
println("--- test filter ---") | |
val f2 = (x: Int) => x % 2 == 0 | |
test(myList.filter(f2), list.filter(f2)) | |
println("--- test groupBy ---") | |
val f3 = (x: Int) => x % 3 | |
test(myList.groupBy(f3), list.groupBy(f3)) | |
println("--- test foldLeft ---") | |
val f4 = (x: Int, y: Int) => x + y | |
test(myList.foldLeft(0)(f4), list.foldLeft(0)(f4)) | |
println("--- test reduce ---") | |
val f5 = (x: Int, y: Int) => x + y | |
test(myList.reduce(f5), list.reduce(f5)) | |
println("--- test partition ---") | |
val f6 = (x: Int) => x % 2 == 0 | |
test(myList.partition(f6), list.partition(f6)) | |
println("--- test foreach ---") | |
val f7 = (x: Int) => print(s"$x -> ") | |
myList.foreach(f7) | |
println() | |
list.foreach(f7) | |
println() | |
println() | |
println("--- test forall ---") | |
val f8 = (x: Int) => x < 100 | |
test(myList.forall(f8), list.forall(f8)) | |
val f9 = (x: Int) => x > 5 | |
test(myList.forall(f9), list.forall(f9)) | |
println("--- test count ---") | |
val f10 = (x: Int) => x % 2 == 0 | |
test(myList.count(f10), list.count(f10)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment