1

Is there any equivalent of the following function in Scala's standard library?

def traverse[A, B](collection: List[A])(f: A => Option[B]): Option[List[B]]

traverse applies a function that can fail to an immutable list. It returns None at the first failure. It returns Some(list) if everything went fine.

Here I'm using lists, but it could be immutable hash maps for example.

Antoine
  • 1,782
  • 1
  • 14
  • 32
  • Probably not, this seems very specific. It's not really clear what this is supposed to do, either. What determines if `Option[List[B]` is `Some` or `None`? – Michael Zajac Dec 16 '14 at 15:20
  • 2
    Looks like `traverseU` from `scalaz`. – senia Dec 16 '14 at 15:25
  • I'm sorry for not being clear enough. I added the behaviour of `traverse` to my question. – Antoine Dec 16 '14 at 15:27
  • Is this a duplicate of http://stackoverflow.com/q/23914713? That person seems to have been trying to implement something similar. No one found a simple standard library function to answer that question, though. – Dan Getz Dec 16 '14 at 15:27
  • @senia Thanks it seems to be what I'm looking for. I'll try it ASAP. – Antoine Dec 16 '14 at 15:35

2 Answers2

1

As it was mentioned in comments scalaz traverseU is exactly what you want

  import scalaz._
  import Scalaz._

  val list = List(1, 2, 3, 4)

  println(list.traverseU(i => Option(i+1)))
  println(list.traverseU(i => if (i>2) Option(i+1) else None))

Output:

Some(List(2, 3, 4, 5))
None

Update

With Map it's a little more complicated

  val map = Map("a" -> 1, "b" -> 2, "c" -> 3)

 map.toList.traverseU { case (k, v) => Option((k, v+1)) } map (_.toMap)
 map.toList.traverseU { case (k, v) => if (v > 2) Option((k, v)) else None } map (_.toMap)
Eugene Zhulenev
  • 9,714
  • 2
  • 30
  • 40
0

You could use traverseU from scalaz for both Lists and Maps:

import scalaz._, Scalaz._

(1 to 3).toList.traverseU{ x => (x > 0) option x }
// Some(List(1, 2, 3))

(1 to 3).toList.traverseU{ x => (x > 1) option x }
// None

import scalaz.std.map._

val m = Map('a -> 1, 'b -> 2, 'c -> 3)

m.traverseU{ x => (x > 1) option x }
// None

m.traverseU{ x => (x > 0) option x }
// Some(Map('a -> 1, 'b -> 2, 'c -> 3))

You could also use it with indexedSeq, set and vector with additional import from scalaz.std.<instancesObject>._.

import scalaz.std.indexedSeq._

(1 to 3).traverseU{ _.some }
// Option[IndexedSeq[Int]] = Some(Vector(1, 2, 3))

You could also implement Traverse to use it with other collections.

senia
  • 37,745
  • 4
  • 88
  • 129