75

If I have something like a List[Option[A]] and I want to convert this into a List[A], the standard way is to use flatMap:

scala> val l = List(Some("Hello"), None, Some("World"))
l: List[Option[java.lang.String]] = List(Some(Hello), None, Some(World))

scala> l.flatMap( o => o)
res0: List[java.lang.String] = List(Hello, World)

Now o => o is just an identity function. I would have thought there'd be some way to do:

l.flatMap(Identity) //return a List[String]

However, I can't get this to work as you can't generify an object. I tried a few things to no avail; has anyone got something like this to work?

giampaolo
  • 6,906
  • 5
  • 45
  • 73
oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
  • 3
    I'd think that `{_}` should equate to `{x => x}` just as `{_ + 3}` equates to `{x => x+3}`. Can anyone comment on why it is not so? – Randall Whitman Dec 06 '16 at 01:38

4 Answers4

72

There's an identity function in Predef.

l flatMap identity[Option[String]]

> List[String] = List(Hello, World)

A for expresion is nicer, I suppose:

for(x <- l; y <- x) yield y

Edit:

I tried to figure out why the the type parameter (Option[String]) is needed. The problem seems to be the type conversion from Option[T] to Iterable[T].

If you define the identity function as:

l.flatMap( x => Option.option2Iterable(identity(x)))

the type parameter can be omitted.

Ricardo
  • 3,696
  • 5
  • 36
  • 50
Thomas Jung
  • 32,428
  • 9
  • 84
  • 114
  • How come the type inferencer can't figure out the types itself? Why doesn't `l.flatMap(identity): List[String]` work? – oxbow_lakes Nov 25 '09 at 15:37
  • I thought that the inferencer could figure that out. I have no idea. I'll add a question. :-) – Thomas Jung Nov 25 '09 at 15:42
  • 1
    @oxbow_lakes - See edit. It is related to implicit type conversions. – Thomas Jung Nov 25 '09 at 16:22
  • @Thomas - thanks. A shame about the identity/Option/Iterable thing as it seems like this is one of the primary places where it's likely to be used. Unfortunately it's less readable with identity than without – oxbow_lakes Nov 25 '09 at 17:09
  • This solution doesn't seem to work in scala 2.9.1. `l flatMap identity[Option[String]] :9: error: polymorphic expression cannot be instantiated to expected type; found : Option[String] => Option[String] required: Option[java.lang.String] => scala.collection.GenTraversableOnce[?] l flatMap identity[Option[String]] ^` – devth Jul 19 '12 at 15:52
24

FWIW, on Scala 2.8 you just call flatten on it. Thomas has it mostly covered for Scala 2.7. He only missed one alternative way of using that identity:

l.flatMap[String](identity)

It won't work with operator notation, however (it seems operator notation does not accept type parameters, which is good to know).

You can also call flatten on Scala 2.7 (on a List, at least), but it won't be able to do anything without a type. However, this works:

l.flatten[String]
Community
  • 1
  • 1
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
4

You could just give the type inferencer a little help:

scala> val l = List(Some("Hello"), None, Some("World"))
l: List[Option[java.lang.String]] = List(Some(Hello), None, Some(World))

scala> l.flatten[String]
res0: List[String] = List(Hello, World)
David Winslow
  • 8,472
  • 1
  • 31
  • 27
0

Scala 3:

List(1,2,3).map(identity)

// val res0: List[Int] = List(1, 2, 3)
Joe
  • 85
  • 6