Zuerst ignorieren Sie einfach die Einschränkungen und denken über die flatMap
Funktion in diesem Fall nach. Sie haben eine List[A]
und eine Funktion f: A => List[B]
. Normalerweise, wenn Sie nur eine map
auf der Liste und wenden Sie die f
Funktion, erhalten Sie wieder eine List[List[B]]
, richtig? Also, um eine List[B]
zu bekommen, was würdest du tun? Sie würden über die List[List[B]]
eine List[B]
zurückbekommen, indem Sie einfach alle Elemente in die List[List[B]]
anhängen. So wird der Code aussehen etwas wie folgt aus:
def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
val tmp = xs.map(f) // List[List[B]]
tmp.foldRight(List[B]())((outCurr, outAcc) => outCurr ++ outAcc)
}
Um zu überprüfen, was wir haben, so weit, laufen Sie den Code in REPL und überprüfen Sie das Ergebnis mit integrierten in flatMap
Methode:
scala> def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
| val tmp = xs.map(f) // List[List[B]]
| tmp.foldRight(List[B]())((outCurr, outAcc) => outCurr ++ outAcc)
| }
flatMap: [A, B](xs: List[A])(f: A => List[B])List[B]
scala> flatMap(List(1, 2, 3))(i => List(i, 2*i, 3*i))
res0: List[Int] = List(1, 2, 3, 2, 4, 6, 3, 6, 9)
scala> List(1,2,3).flatMap(i => List(i, 2*i, 3*i))
res1: List[Int] = List(1, 2, 3, 2, 4, 6, 3, 6, 9)
OK, so Sehen Sie sich nun unsere Einschränkungen an, wir dürfen map
hier nicht verwenden. Aber das brauchen wir nicht wirklich, denn die map
hier ist nur zum Durchlaufen der Liste xs
. Wir können dann für diesen Zweck verwenden. Also lassen Sie uns schreiben die map
Teil mit foldRight
:
def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
val tmp = xs.foldRight(List[List[B]]())((curr, acc) => f(curr) :: acc) // List[List[B]]
tmp.foldRight(List[B]())((outCurr, outAcc) => outCurr ++ outAcc)
}
OK, lassen Sie uns den neuen Code überprüfen:
scala> def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
| val tmp = xs.foldRight(List[List[B]]())((curr, acc) => f(curr) :: acc) // List[List[B]]
| tmp.foldRight(List[B]())((outCurr, outAcc) => outCurr ++ outAcc)
| }
flatMap: [A, B](xs: List[A])(f: A => List[B])List[B]
scala> flatMap(List(1, 2, 3))(i => List(i, 2*i, 3*i))
res3: List[Int] = List(1, 2, 3, 2, 4, 6, 3, 6, 9)
OK, so weit so gut. Lassen Sie uns also den Code etwas optimieren, anstatt zwei aufeinanderfolgende foldRight
zu haben, werden wir sie in nur einem foldRight
kombinieren. Das sollte nicht allzu schwierig sein:
def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
xs.foldRight(List[B]()) { (curr, acc) => // Note: acc is List[B]
val tmp2 = f(curr) // List[B]
tmp2 ++ acc
}
}
Überprüfen Sie erneut:
scala> def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
| xs.foldRight(List[B]()) { (curr, acc) => // Note: acc is List[B]
| val tmp2 = f(curr) // List[B]
| tmp2 ++ acc
| }
| }
flatMap: [A, B](xs: List[A])(f: A => List[B])List[B]
scala> flatMap(List(1, 2, 3))(i => List(i, 2*i, 3*i))
res4: List[Int] = List(1, 2, 3, 2, 4, 6, 3, 6, 9)
OK, also lassen Sie uns unsere Zwänge aus, es sieht aus wie wir nicht ++
Betrieb nutzen können.Nun, ++
ist nur ein Weg, um die beiden List[B]
zusammenhängen, so können wir mit Sicherheit die gleiche Sache mit foldRight
Verfahren erreichen, wie folgt aus:
def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
xs.foldRight(List[B]()) { (curr, acc) => // Note: acc is List[B]
val tmp2 = f(curr) // List[B]
tmp2.foldRight(acc)((inCurr, inAcc) => inCurr :: inAcc)
}
}
Und dann haben wir sie alle in einer Zeile durch kombinieren:
def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] =
xs.foldRight(List[B]())((curr, acc) =>
f(curr).foldRight(acc)((inCurr, inAcc) => inCurr :: inAcc))
ist es nicht die gegebene Antwort :)
Perfekte Klarheit, danke! – deterjan
Gern geschehen! –