Vandexel
Vandexel

Reputation: 639

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?

Upvotes: 0

Views: 165

Answers (3)

Ori Popowski
Ori Popowski

Reputation: 10672

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)

Upvotes: 1

Nagarjuna Pamu
Nagarjuna Pamu

Reputation: 14825

Product List using only map and flatten

val nums = List(1, 2, 3)
val chars = List('a', 'b')

nums.map { a => chars.map { b => (a, b) } }.flatten

Scala REPL

scala> nums.map(a => chars.map(b => (a, b)))
res5: List[List[(Int, Char)]] = List(List((1, 'a'), (1, 'b')), List((2, 'a'), (2, 'b')), List((3, 'a'), (3, 'b')))
scala> nums.map(a => chars.map(b => (a, b))).flatten
res6: List[(Int, Char)] = List((1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b'))

Product List can be built using flatMap and map combination

nums.flatMap { a => chars.map { b => (a, b) }} 

Product List can also be built using for comprehension

for {a <- nums; b <- chars} yield (a, b)

Scala REPL

scala> val nums = List(1, 2, 3)
val nums: List[Int] = List(1, 2, 3)

scala> val chars = List('a', 'b')
chars: List[Char] = List('a', 'b')

scala> nums.flatMap { a => chars.map { b => (a, b) }}
res2: List[(Int, Char)] = List((1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b'))

scala> for {a <- nums; b <- chars} yield (a, b)
res3: List[(Int, Char)] = List((1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b'))

Upvotes: 2

Samar
Samar

Reputation: 2101

val ls1 = List(1,2,3) 
val ls2 = List('a','b') 
def product[A](xs: List[A], ys: List[A])= xs.map(x => ys.map((x,_))).flatten 

product(ls1,ls2) 

Upvotes: 1

Related Questions