Bagaimana kita menjelaskan Map dan FlatMap dalam Scala kepada programmer pemula?

Kadang kita tidak bisa menjelaskan sesuatu yg sering kita pakai dalam code yg kita tulis. Salah satu nya adalah Map dan FlatMap. Dua fungsi ini sangat populer dan merupakan penerapan dari higher-order function. Jadi kita bisa menuliskan sebuah function yg nantinya akan memproses atau menggunakan setiap elemen sebagai input.

def map[B](f: A => B): Traversable[B]

Code di atas adalah definisi map secara umum di scala dalam trait Traversable[A]. A dan B adalah generic type dimana A adalah source element type dan B adalah result element type. Lebih mudah jika saya memberikan contoh nya:


scala> val a = List(1, 2, 3)
val a: List[Int] = List(1, 2, 3)

scala> a.map(x => x.toString)
val res66: List[String] = List(1, 2, 3)

Dalam contoh ini, kita menggunakan Map function untuk mengubah List[Int] menjadi List[String]. Generic type A dalam case ini adalah Int dan Generic type B nya adalah String karena kita mengembalikan tipe String. Collection type pada result masih tetap sama, yaitu sebuah List. Map function akan membuat sebuah collection baru dengan menerapkan block function yg kita tulis (x -> x.toString).

Bagaimana dengan FlatMap? Jika map hanya menerapakan function yg kita tulis saat membuat collection baru, flatMap akan menjalankan flatten/merge collection result dari function yg kita tulis setelah menjalankannya pada masing-masing internal elemen. Maka kita perlu mengembalikan sebuah collection pada function yg kita tulis agar proses flatten tidak error.

Berikut ini adalah contoh error saat kita menggunakan flatMap pada sebuah List[Int]:

scala> val a = List(1,2,3)
val a: List[Int] = List(1, 2, 3)

scala> a.map(x=>x)
val res52: List[Int] = List(1, 2, 3)

scala> a.flatMap(x=>x)
                    ^
       error: type mismatch;
        found   : Int
        required: scala.collection.IterableOnce[?]

Perbedaan penggunaan map dan flatMap yang sangat jelas bisa kita lihat saat menggunakannya pada sebuah String:

scala> val a = List("map", "flatMap")
val a: List[String] = List(map, flatMap)

scala> a.map(_.toUpperCase)
val res61: List[String] = List(MAP, FLATMAP)

scala> a.flatMap(_.toUpperCase)
val res62: List[Char] = List(M, A, P, F, L, A, T, M, A, P)

scala> a.map(_.toUpperCase).flatten
val res63: List[Char] = List(M, A, P, F, L, A, T, M, A, P)

Pada flatMap jumlah elemen dalam result bisa saja berbeda dengan jumlah elemen dalam source. Ini terjadi ketika result dari function yg kita tulis adalah collection kosong atau mengembalikan collection dengan jumlah elemen lebih dari satu. Berikut ilustrasinya:

scala> val a = List("map", "flatMap")
val a: List[String] = List(map, flatMap)

scala> a.flatMap(x => if(x.contains("flat")){List(x)}else{None})
val res64: List[String] = List(flatMap)

scala> a.flatMap(x => if(x.contains("flat")){List(x)}else{List("no", "flat")})
val res65: List[String] = List(no, flat, flatMap)

bersambung…

Leave a Reply