Is there any difference between flatten and flatMap(identity)?
Asked Answered
L

3

13
scala> List(List(1), List(2), List(3), List(4))
res18: List[List[Int]] = List(List(1), List(2), List(3), List(4))

scala> res18.flatten
res19: List[Int] = List(1, 2, 3, 4)

scala> res18.flatMap(identity)
res20: List[Int] = List(1, 2, 3, 4)

Is there any difference between these two functions? When is it appropriate to use one over the other? Are there any tradeoffs?

Letti answered 18/11, 2014 at 22:14 Comment(0)
P
15

You can view flatMap(identity) as map(identity).flatten. (Of course it is not implemented that way, since it would take two iterations).

map(identity) gives you the same collection, so in the end it is the same as only flatten.

I would personally stick to flatten, since it is shorter/easier to understand and designed to exactly do this.

Pringle answered 18/11, 2014 at 22:33 Comment(0)
H
7

Conceptually there is no difference in the result... flatMap is taking bit more time to produce same result...

I will show it more practically with an example of flatMap, map & then flatten and flatten

object Test extends App {
  // flatmap
  println(timeElapsed(List(List(1, 2, 3, 4), List(5, 6, 7, 8)).flatMap(identity)))
  // map and then flatten
  println(timeElapsed(List(List(1, 2, 3, 4), List(5, 6, 7, 8)).map(identity).flatten))
  // flatten
  println(timeElapsed(List(List(1, 2, 3, 4), List(5, 6, 7, 8)).flatten))

  /**
   * timeElapsed
   */
  def timeElapsed[T](block: => T): T = {
    val start = System.nanoTime()
    val res = block
    val totalTime = System.nanoTime - start
    println("Elapsed time: %1d nano seconds".format(totalTime))
    res
  }
}


Both flatMap and flatten executed with same result after repeating several times

Conclusion : flatten is efficient

Elapsed time: 2915949 nano seconds
List(1, 2, 3, 4, 5, 6, 7, 8)
Elapsed time: 1060826 nano seconds
List(1, 2, 3, 4, 5, 6, 7, 8)
Elapsed time: 81172 nano seconds
List(1, 2, 3, 4, 5, 6, 7, 8)
Himation answered 14/8, 2017 at 10:23 Comment(0)
U
3

Conceptually, there is no difference. Practically, flatten is more efficient, and conveys a clearer intent.

Generally, you don't use identity directly. It's more there for situations like it getting passed in as a parameter, or being set as a default. It's possible for the compiler to optimize it out, but you're risking a superfluous function call for every element.

You would use flatMap when you need to do a map (with a function other than identity) immediately followed by a flatten.

Unlicensed answered 18/11, 2014 at 22:36 Comment(5)
The last sentence ("You would use..") is misleading, flatmap can't always be replace with map + flatten and it normally conveys a different computationCorneliuscornell
@Chirlo, I think you are mistaken there, but I'm willing to admit if I am wrong. Can you please provide a counterexample?Unlicensed
with map + flatten you'll always get a List with the same number of elements as the original. With flatmap you could can do more manipulations, like list.flatmap( x => if (x > 2 ) List(x,x,x,x) else List()). This would yield ( from the OPs example) : List(3,3,3,3,4,4,4,4). You can implement filter, takeWhile.... in terms of flatMap, which you can't do with map+flattenCorneliuscornell
Your first example with map+flatten is list.map(x=>if (x>2) List(x,x,x,x) else List()).flatten. filter is list.map(x => if (pred(x)) List(x) else List()).flatten.Unlicensed
Oh, ok, I missunderstood the example, but you can get into situations where both are not equivalent, because of scala's signature of flatmap (with CanBuildFrom).Corneliuscornell

© 2022 - 2024 — McMap. All rights reserved.