Vandexel Vandexel - 2 months ago 12
Scala Question

Scala pairs using map and flatten

I'm working on a problem to take two lists, for example (1,2,3) and (a,b) and return a list ((1,a)(1,b)(2,a)(2,b)(3,a)(3,b)) using only map and flatten.

This problem requires me to define a function as follows:

def product[A](xs: List[A], ys: List[A])= {


And within this function get the result. I'm rather new to Scala and I am used to languages like python and java.

I've gotten this far:

def product[A](xs: List[A], ys: List[A])= {
for(y <- ys){
println(xs.map(x=> (x,y)))
}
}


This will return something like this:

List((1,a), (2,a), (3,a))

List((1,b), (2,b), (3,b))

I'm not sure how can combine these lists now. In python I would do something like create a new list variable, append both of these lists to that list, and then flatten it so I would have one list. However, I'm rather confused by scala as it seems as if I am not allowed to define a new variable within a function. How can I combine these lists and flatten them at this point?

Answer

You can solve it using for comprehension. It's actually a syntactic sugar for map and flatMap:

def product[A](xs: List[A], ys: List[A])= {
    for {
      x <- xs
      y <- ys
    } yield {
      x -> y
    }
}

For-comprehensions is the Scala idiomatic way to achieve this. It's more readable and maintainable, and the underlying operations are still map and flatMap. In fact, even for types that are not collections, but still have map and flatMap, it's common to use for comprehensions (Futures, Options, Trys, etc.)

Edit

If you want to continue with your solution and save the lists and combine them, you'll have to drop the println and add a yield, and then flatten the main list that was created:

def product[A](xs: List[A], ys: List[A]) = {
  for (y <- ys) yield {
    xs.map(x => (x, y))
  }
}

val res = product(List(1, 2, 3), List("a", "b"))

println(res.flatten)