Andrew Cassidy
Andrew Cassidy

Reputation: 2998

Cartesian product (combinations) with empty Seq

I'd like the cartesian product (combinations) of three Seqs in scala. Any of them can be empty. I know the cartesian product of any Set with the Empty set is the empty set. I'd like a work around to supply a default value ("" in the example below). Here's the skeleton code.

val letters = Seq("a", "b")
val numbers = Seq("1")
val empty: Seq[String] = Nil
// Desired output = Seq(("a", "1", ""), ("b", "1", ""))

// Cartesian product
// What I'm trying which returns List()
for {
 l <- letters
 n <- numbers
 e <- empty
} yield {
    (l, n, e)
}

So far I've tried lift and orElse(Seq("")). The problem with orElse is that it returns a PartialFunction and I loose the ability to map or flatMap.

Upvotes: 1

Views: 141

Answers (1)

Dan Gallagher
Dan Gallagher

Reputation: 1022

If your default value is known beforehand, you can create a list of a single element with the default value:

def nonEmptyOrDefault[A](xs: Seq[A], default: A): Seq[A] =
  if (xs.isEmpty) Seq(default)
  else xs

for {
  l <- nonEmptyOrDefault(letters, "")
  n <- nonEmptyOrDefault(numbers, "")
  e <- nonEmptyOrDefault(empty, "")
} yield (l, n, e)

Or you can use a collection that ensures non-emptiness

class NESeq[+A] private (private val xs: Iterable[A]) {
  // TODO implement flatMap, map, ++, etc.
}

object NESeq {
  def fromIterable[A](xs: Iterable[A]): Option[NESeq[A]] =
    if (xs.isEmpty) None
    else Some(new NESeq(xs))
}

Upvotes: 2

Related Questions