I'm wondering what the idiomatic way in Scala would be to convert a Seq
of Option[A]
to an Option[Seq[A]]
, where the result is None
if any of the input options were None
.
Asked
Active
Viewed 177 times
1

John
- 2,575
- 1
- 17
- 29
-
3See https://stackoverflow.com/questions/28753777/converting-listoptiona-to-an-optionlista-in-scala and https://stackoverflow.com/questions/52546860/need-to-convert-a-seqoptiona-to-optionseqa. – Alexey Romanov Jun 15 '21 at 18:16
2 Answers
3
The idiomatic way is probably to use what is generally called traverse
.
I'd recommend reading Cats' documentation about it: https://typelevel.org/cats/typeclasses/traverse.html
With Cats, it would be as easy as:
import cats.implicits
val list = List(Some(1), Some(2), None)
// list: List[Option[Int]] = List(Some(1), Some(2), None)
val traversed = list.traverse(identity)
// traversed: Option[List[Int]] = None
// Or in this specific case:
val sequenced = list.sequence
// sequenced: Option[List[Int]] = None

Gaël J
- 11,274
- 4
- 17
- 32
3
Standard library provides partitionMap
which helps implement sequence
operation
_.partitionMap(_.toRight("")) match {
case (Nil, xs) => Some(xs)
case _ => None
}
Here is a possible generic implementation as extension method
extension [CC[x] <: IterableOps[x, CC, CC[x]], A](xs: CC[Option[A]])
def sequence: Option[CC[A]] =
xs.partitionMap(_.toRight("")) match {
case (lefts, as) if lefts.isEmpty => Some(as)
case _ => None
}

Mario Galic
- 47,285
- 6
- 56
- 98
-
2Very nice, but use of `Nil` restricts the possible collection types. Alternative: `.pipe(tup => if (tup._1.isEmpty) Some(tup._2) else None)` – jwvh Jun 15 '21 at 20:18