18

I am trying to implement my own generic flatten for list objects which hold lists in Scala. At this point I have

def myFlatten[T](list: List[List[t]]): List[T] = {
    for (xs <- list)
        for (x <- xs) yield x
}

I am getting a message:

for xs found Unit required list.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
topless
  • 8,069
  • 11
  • 57
  • 86

3 Answers3

24
def myFlatten[T](list : List[List[T]]) = for(xs <- list; x <- xs) yield x
Viktor Klang
  • 26,479
  • 7
  • 51
  • 68
13

Very close! Here's one that works:

scala> def myFlatten[T](list: List[List[T]]): List[T] = for (xs <- list; x <- xs) yield x 
myFlatten: [T](list: List[List[T]])List[T]

Or use the built-in flatten

scala> List(List(1, 2), List(3)).flatten
res0: List[Int] = List(1, 2, 3)

scala> List(Set(1, 2), Set(3)).flatten  
res1: List[Int] = List(1, 2, 3)

It's instructive to see how to write this function without the for syntactic sugar.

scala> def myFlatten[T](list: List[List[T]]): List[T] = list flatMap identity
myFlatten: [T](list: List[List[T]])List[T]

scala> myFlatten(List(List(1, 2), List(3)))
res3: List[Int] = List(1, 2, 3)

UPDATE

BTW, the fact that List[List[T]] can be flattened to List[T] is 50% of the reason that List is a Monad. Generally, this is known as join. The other 50% comes from the fact you can map a function A => B across a List[A] to result in a List[B]. The general name for this is a Functor map. fmap and join on Wikipedia.

A different way of defining a Monad for type constructor M is with a pure operation, that takes a value of type A, and returns a M[A]; and a bind operation that takes an M[A], a function A => M[B], and results in M[B]. For Lists, pure == List(_), and bind = (l: List[A], f: (A => List[B])) => l.flatMap(f)

retronym
  • 54,768
  • 12
  • 155
  • 168
6

Personally, I like this style:

def myFlatten[T](list: List[List[t]]): List[T] = for {
  xs <- list
  x <- xs
} yield x
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681