spark example scala map

scala - example - Mapa versus FlatMap en String



scala map example (5)

Con el map estás tomando una lista de caracteres y convirtiéndola en una lista de cadenas. Ese es el resultado que ves. Un map nunca cambia la longitud de una lista: la lista de cadenas tiene tantos elementos como la cadena original tiene caracteres.

Con flatMap está tomando una lista de caracteres y convirtiéndola en una lista de cadenas y luego flatMap a flatMap en una sola cadena . flatMap es útil cuando desea convertir un elemento en una lista en varios elementos, sin crear una lista de listas. (Por supuesto, esto también significa que la lista resultante puede tener cualquier longitud, incluido 0, esto no es posible con el map menos que empiece con la lista vacía).

Al escuchar la lección de Colecciones de los Principios de Programación Funcional en Scala , vi este ejemplo:

scala> val s = "Hello World" scala> s.flatMap(c => ("." + c)) // prepend each element with a period res5: String = .H.e.l.l.o. .W.o.r.l.d

Entonces, tenía curiosidad de por qué el Sr. Odersky no usaba un map aquí. Pero, cuando probé el mapa, obtuve un resultado diferente del que esperaba.

scala> s.map(c => ("." + c)) res8: scala.collection.immutable.IndexedSeq[String] = Vector(.H, .e, .l, .l, .o, ". ", .W, .o, .r, .l,

Esperaba que la llamada anterior devuelva una Cadena, ya que estoy mapeando, es decir, aplicando una función a cada elemento en la "secuencia" y luego devolviendo una nueva "secuencia".

Sin embargo, podría realizar un map lugar de un flatmap para una List[String] :

scala> val sList = s.toList sList: List[Char] = List(H, e, l, l, o, , W, o, r, l, d) scala> sList.map(c => "." + c) res9: List[String] = List(.H, .e, .l, .l, .o, ". ", .W, .o, .r, .l, .d)

¿Por qué un IndexedSeq[String] el tipo de retorno del map de llamada en el String?


La razón de este comportamiento es que, para aplicar el "mapa" a una Cadena, Scala trata la cadena como una secuencia de caracteres ( IndexedSeq[String] ). Esto es lo que se obtiene como resultado de la invocación del mapa, donde se aplica la operación para cada elemento de dicha secuencia. Dado que Scala trató la cadena como una secuencia para aplicar el map , eso es lo que devuelve el map .

flatMap entonces simplemente invoca al flatMap en esa secuencia luego, lo que luego lo "convierte" nuevamente en una Cadena


Su función de mapa c => ("." + c) toma un carácter y devuelve un String. Es como tomar una lista y devolver una lista de listas. flatMap aplana esa espalda.

Si devolviera un char en lugar de una cadena, no necesitaría que el resultado se aplanara, por ejemplo, "abc".map(c => (c + 1).toChar) devuelve "bcd".


También tiene una interesante " colección de ejemplos de Scala flatMap ", el primero de los cuales ilustra esa diferencia entre flatMap y el map :

scala> val fruits = Seq("apple", "banana", "orange") fruits: Seq[java.lang.String] = List(apple, banana, orange) scala> fruits.map(_.toUpperCase) res0: Seq[java.lang.String] = List(APPLE, BANANA, ORANGE) scala> fruits.flatMap(_.toUpperCase) res1: Seq[Char] = List(A, P, P, L, E, B, A, N, A, N, A, O, R, A, N, G, E)

Toda una diferencia, ¿verdad?
Como flatMap trata una String como una secuencia de Char , aplana la lista resultante de cadenas en una secuencia de caracteres ( Seq[Char] ).
flatMap es una combinación de map y flatten , por lo que primero ejecuta el map en la secuencia, luego se flatten , dando el resultado que se muestra.

Puedes ver esto ejecutando el mapa y luego aplanándote:

scala> val mapResult = fruits.map(_.toUpperCase) mapResult: Seq[String] = List(APPLE, BANANA, ORANGE) scala> val flattenResult = mapResult.flatten flattenResult: Seq[Char] = List(A, P, P, L, E, B, A, N, A, N, A, O, R, A, N, G, E)


Use flatMap en situaciones en las que ejecute map seguido de flattern . La situación específica es esta:

• Estás usando un mapa (o una expresión for / yield ) para crear una nueva colección a partir de una colección existente.

• La colección resultante es una lista de listas.

Llamas a aplanar inmediatamente después del mapa (o una expresión para / rendimiento ).

Cuando estás en esta situación, puedes usar flatMap en su lugar.

Ejemplo: Añadir todos los números enteros de la bolsa

val bag = List("1", "2", "three", "4", "one hundred seventy five") def toInt(in: String): Option[Int] = { try { Some(Integer.parseInt(in.trim)) } catch { case e: Exception => None } }

Usando un método flatMap

> bag.flatMap(toInt).sum

Usando el método del mapa (3 pasos necesarios)

bag.map(toInt) // List[Option[Int]] = List(Some(1), Some(2), None, Some(4), None) bag.map(toInt).flatten //List[Int] = List(1, 2, 4) bag.map(toInt).flatten.sum //Int = 7