Why do .map.flatten and flatMap on a Scala Map return different results?

scala flatten
scala flatmap on map
scala flatmap future
scala flatmap implementation
scala flatmap option
scala map function
map and increment function in scala
scala map to list

I heard many people say flatMap is similar to map + flatten. For example, the answer.

Quite a difference, right? Because flatMap treats a String as a sequence of Char, it flattens the resulting list of strings into a sequence of characters (Seq[Char]). flatMap is a combination of map and flatten, so it first runs map on the sequence, then runs flatten giving the result shown.

But I have some code problems today. The result of map and flatMap seems to be different. Here are my code

object ListDemo {
  def main(args: Array[String]): Unit = {
    val map1 = Map("a" -> List(1 ->11,1->111), "b" -> List(2 -> 22, 2 ->222)).map(_._2).flatten
    val map2 = Map("a" -> List(1 ->11,1->111), "b" -> List(2 -> 22, 2 ->222)).flatMap(_._2)
    map1.foreach(println)
    println()
    map2.foreach(println)
  }
}

the result is not expected.

(1,11)
(1,111)
(2,22)
(2,222)

(1,111)
(2,222)

Why it happened?


When calling .map(f) on a Map with an f that returns (K, V) for some K and V (not necessarily the same K and V types of the original Map), the result will be a Map[K, V]. Otherwise, if f returns some other (non-pair) type T, the result will be an Iterable[T]. So it will be a Map if the function returns a pair and an Iterable otherwise.

In your case the function returns List[(Int, Int)], so the result is an Iterable[List[(Int, Int)]] - not a Map. The .flatten then turns this into an Iterable[(Int, Int)].

When using flatMap directly, you directly end up with the (Int, Int) pairs, so the result will be a Map[Int, Int] - not an Iterable[(Int, Int)]. And since Maps don't allow duplicate keys, the Map contains less elements than the Iterable.

A collection of Scala 'flatMap' examples, I like to think of flatMap as a combination of map followed by flatten , so it first that converts a String to an Int , and returns its result as an Option[Int] : Although there are other ways to get the values from a Scala map , you  The usage of map function, as the name implies, passes a function into map, and then uses the passed function to process each element in the collection and return the processed result. The only difference between flat map and map is that the return value of the incoming function must be list after processing, which is not hard to understand.


TL;DR: the result type of both calls is different. The call to .map().flatten returns a Iterable[(Int, Int)] and the call to .flatMap() returns a Map[Int, Int]. Since a map may not contain the same key twice, the first entry per key is overwritten by the second entry.

Consider a Map as a Iterable[(Key,Value)]. When calling .map, you will have to provide it a function that returns a tuple, (Key, Value) (the actual types may be different from the original Key and Value).

In your example, Value happens to be a List[(Int, Int)]. When calling .map, and returning the Value of the original Map, you end up with a Iterable[List[(Int, Int)]], which your call to .flatten turns into a Iterable[(Int, Int)] by concatenating the 'inner' lists together. If you were to turn that into a map (by calling .toMap), you would see the same result as with flatMap.

Now, flatMap is different in that it expects a return type of Seq[(Key, Value)], rather than just (Key, Value). It then uses the returned value as the entries in a newly constructed Map.

In your case, your original Value of List[(Int, Int)] satisfies the expected return type, converting you original Map[(String, List[(Int, Int)] into a Map[(Int, Int)]. Since a map cannot contain two entries with the same keys, the second occurrence of the key replaces the earlier occurrence.

To see this behavior, it helps to use the REPL (just run scala) instead of writing a main class, so you can see the intermediate values and their types.

scala> val theMap = Map("a" -> List(1 ->11,1->111), "b" -> List(2 -> 22, 2 ->222))
theMap: scala.collection.immutable.Map[String,List[(Int, Int)]] = Map(a -> List((1,11), (1,111)), b -> List((2,22), (2,222)))

scala> val mapped = theMap.map(_._2)
mapped: scala.collection.immutable.Iterable[List[(Int, Int)]] = List(List((1,11), (1,111)), List((2,22), (2,222)))

scala> val flattened = mapped.flatten
flattened: scala.collection.immutable.Iterable[(Int, Int)] = List((1,11), (1,111), (2,22), (2,222))

scala> val flatMapped = theMap.flatMap(_._2)
flatMapped: scala.collection.immutable.Map[Int,Int] = Map(1 -> 111, 2 -> 222)

scala> val flattenedToMap = flattened.toMap
flattenedToMap: scala.collection.immutable.Map[Int,Int] = Map(1 -> 111, 2 -> 222)

How to use Scala Maps and FlatMaps, Scala's map method is exceptionally powerful, and its uses are heavily Collection types other than List behave similarly, using their internal iterators to function would never execute, and we would get None as a result instead: When combining Options with collections, flatten and flatMap allow us to  This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 10.16, “How to Combine map and flatten with flatMap”. Problem. When you first come to Scala from an object-oriented programming background, the flatMap method can seem very foreign, so you’d like to understand how to use it and see where it can be applied.


You are kind of misunderstanding things here,

So, Lets say you have x: M[A] and f: A = N[B]for any Monad M and N then x.flatMap(f) should be same as x.map(f).flatten.

But what you have here is kind of a nested monad map: M[N[A]] and your function is f: A => B with following aliasing,

scala> type MapWithStringKey[A] = Map[String, A]
// defined type alias MapWithStringKey

scala> type TupleOfInt = (Int, Int)
// defined type alias TupleOfInt

scala> val map: MapWithStringKey[List[TupleOfInt]] = Map("a" -> List(1 ->11,1->111), "b" -> List(2 -> 22, 2 ->222))
// map: MapWithStringKey[List[TupleOfInt]] = Map(a -> List((1,11), (1,111)), b -> List((2,22), (2,222)))

This case is entirely different from above mentioned standard definition which connects flatMap to map and flatten.

Now, It is just one of the non-standards cases where you can choose to use either of the two choices depending on what you want. And when we add the special key-uniqueness properties of Map (which is already discussed in answer by @sepp2k), things become even more unpredictable.

Map().flatten != flatMap, flatMap(f) ^. filter1 works but is inefficient since it creates an intermediate Seq. In this example, the results should be equivalent: val xs = Seq(1,2,-1,3) def f(x: Int​) = Option(x).filter(_ >= 0) xs.map(f).flatten xs. should probably return option2iterable from Option's companion, the implementation of which is just calling toList . But in my case I wanted to do something more like flat map in this case, I want a map to come out that misses out the key 1 because it’s value is None. flatMap doesn’t work on maps like mapValues, it get’s passed the tuple and if it returns a List single items you’ll get a list back, but if you return a tuple you’ll get a Map back.


Map, map and flatMap in Scala, One the benefits of Scala is that the functional programming concepts can a sequence for each element in the list, and flattening the results into the original list. Now a map can be implemented a number of different ways, but flatMap doesn't work on maps like mapValues, it get's passed the tuple and  Because of the way flatMap works, it flattens the resulting list of strings into a sequence of characters (Seq [Char]). I like to think of flatMap as a combination of map followed by flatten, so it first runs map on the sequence, then runs flatten, giving the result shown. You can see this by running map and then flatten yourself:


Using Option in Scala, Part 2: map and flatmap - Manning , From Get Programming with Scala by Daniela Sfregola which are common to many Scala types other than Option : understanding Let's see how the functions map , flatten , and flatMap can help you If the optional value is present, map applies the function f to it and wraps the result in a Some instance. In Scala, flatMap () method is identical to the map () method, but the only difference is that in flatMap the inner grouping of an item is removed and a sequence is generated. It can be defined as a blend of map method and flatten method.


Scala, In Scala, flatMap() method is identical to the map() method, but the only So, we can say that flatMap first runs the map method and then the flatten method Here, flatMap is applied on the another function defined in the program and so List(4-1, 4, 4+1)) // After evaluation we get, List(List(1, 2, 3), List(2, 3, 4), List(3, 4, 5)). In this tutorial, we will learn how to use the flatMap function on collection data structures in Scala. The flatMap function is applicable to both Scala's Mutable and Immutable collection data structures. The flatMap method takes a predicate function, applies it to every element in the collection. It then returns a new collection by using the