Cross product in Scala
You can do this pretty straightforwardly with an implicit class and a for
-comprehension in Scala 2.10:
implicit class Crossable[X](xs: Traversable[X]) {
def cross[Y](ys: Traversable[Y]) = for { x <- xs; y <- ys } yield (x, y)
}
val xs = Seq(1, 2)
val ys = List("hello", "world", "bye")
And now:
scala> xs cross ys
res0: Traversable[(Int, String)] = List((1,hello), (1,world), ...
This is possible before 2.10—just not quite as concise, since you'd need to define both the class and an implicit conversion method.
You can also write this:
scala> xs cross ys cross List('a, 'b)
res2: Traversable[((Int, String), Symbol)] = List(((1,hello),'a), ...
If you want xs cross ys cross zs
to return a Tuple3
, however, you'll need either a lot of boilerplate or a library like Shapeless.
cross x_list
and y_list
with:
val cross = x_list.flatMap(x => y_list.map(y => (x, y)))
Here is the implementation of recursive cross product of arbitrary number of lists:
def crossJoin[T](list: Traversable[Traversable[T]]): Traversable[Traversable[T]] =
list match {
case xs :: Nil => xs map (Traversable(_))
case x :: xs => for {
i <- x
j <- crossJoin(xs)
} yield Traversable(i) ++ j
}
crossJoin(
List(
List(3, "b"),
List(1, 8),
List(0, "f", 4.3)
)
)
res0: Traversable[Traversable[Any]] = List(List(3, 1, 0), List(3, 1, f), List(3, 1, 4.3), List(3, 8, 0), List(3, 8, f), List(3, 8, 4.3), List(b, 1, 0), List(b, 1, f), List(b, 1, 4.3), List(b, 8, 0), List(b, 8, f), List(b, 8, 4.3))