Giora Simchoni
Giora Simchoni

Reputation: 3689

scala: complicated flatMap on a tuple of Options

My data type is: List[(Option[Set[Long]], Option[Set[(Long, Long)]])] (i.e. a List of a 2-tuple of Options, one is for a Set of Long, one is for a Set of a 2-tuple of Longs). E.g.:

val l = List((Option(Set(1L, 2L, 3L)), Option(Set((4L, 5L), (6L, 7L)))))

I wish to flatMap this List into a List[Set[Long]] type, in a way that each of the first elements of the second Option, would be concatenated to a new Set with the first Option. So the desired result here is:

List(Set(1L, 2L, 3L, 4L), Set(1L, 2L, 3L, 6L))

This works fine with the following code:

l.flatMap {
 case(setOpt1, setOpt2) =>
 val set1 = setOpt1.getOrElse(Set[Long]());
 val set2 = setOpt2.getOrElse(Set[(Long, Long)]());
 set2.map(k => set1 ++ Set(k._1))
 }

The plot thickens when the second Option is None, and the first Option "exists", e.g.:

val l = List((Option(Set(1L, 2L, 3L)), None))

And assume I have no way of avoiding this. In this case I would like to get the first Set as is:

List(Set(1L, 2L, 3L))

However, using the same code as above the set2 value becomes an empty Set, and the map means nothing in this case, and I would get an empty List:

res60: List[scala.collection.immutable.Set[Long]] = List()

So, how do I do this? Preferably elegantly :)

Upvotes: 2

Views: 1382

Answers (1)

nattyddubbs
nattyddubbs

Reputation: 2095

You could add case statements to handle each combination of Option

def g(l:List[(Option[Set[Long]], Option[Set[(Long, Long)]])]) = l.flatMap{
  case (Some(single), None) =>
    List(single)
  case (Some(single), Some(tuple)) =>
    tuple.map(k => single ++ Set(k._1))
  case (None, Some(tuple)) =>
    tuple.map(k => Set(k._1))
  case (None, None) =>
    List()

}

This produces the result that you are expecting. Here are all the tests I ran:

val l1 = List((Option(Set(1L, 2L, 3L)), Option(Set((4L, 5L), (6L, 7L)))))
g(l1)
res0: List[Set[Long]] = List(Set(1, 2, 3, 4), Set(1, 2, 3, 6))

val l2 = List((Option(Set(1L, 2L, 3L)), None))
g(l2)
res1: List[Set[Long]] = List(Set(1, 2, 3))

val l3 = List((None, Option(Set((4L, 5L), (6L, 7L)))))
g(l3)
res2: List[Set[Long]] = List(Set(4), Set(6))

val l4 = List((None, None))
g(l4)
res3: List[Set[Long]] = List()

Upvotes: 2

Related Questions