Reputation: 639
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
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 (Future
s, Option
s, Try
s, etc.)
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
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
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