views:

104

answers:

2

I have a very large List[A] and a function f: List[A] => List[B]. I would like to split my original list into sub-lists with a maximum size, apply the function to each sublist in turn and then unsplit the result into one big List[B]. This pretty easy:

def split[T](l : List[T], max : Int) : List[List[T]] = //TODO

def unsplit[T](l : List[List[T]]) : List[T] = //TODO

def apply[A, B](l : List[A], f : List[A] => List[B], max : Int) : List[B] = {
  unsplit(split(l, max).map(f(_)))
}

I was wondering whether scalaz supplied standard stuff to do this out of the box? In particular the apply method?

+1  A: 

How about this:

def split[T](ls: List[T],max: Int): List[List[T]] = ls.grouped(max).toList

def unsplit[T](ls: List[List[T]]): List[T] = ls.flatMap(identity)
Eastsun
Well, erm, yes. I said it was easy - I asked whether Scalaz had anything to achieve this out of the box (possibly generalized over other monads)
oxbow_lakes
I'd say that ls.grouped(max) is just as succinct as split(ls,max)
Fred Haslam
+2  A: 

unsplit it just MA#join, for any M[M[A]] where M is a Monad.

split doesn't exist out of the box. The following is a round about way of doing this, more to demonstrate some Scalaz concepts. It actually triggers a stack overflow in the compiler at the moment!

val ls = List(1, 2, 3, 4, 5)
val n = 5

def truesAndFalses(n: Int): Stream[Boolean] = 
  Stream.continually(true.replicate[Stream](n) |+| false.replicate[Stream](n)).join

val grouped: List[List[Int]] = {
  var zipped: List[(Int, Boolean)] = ls.zip(truesAndFalses(2))
  var groupedWithBools: List[List[(Int, Boolean)]] = zipped splitWith {_._2}
  groupedWithBools ∘∘ {pair: (Int, _) => pair._1}
}

val joined: List[Int] = grouped ∘∘ {_ * 2} join
retronym
The trouble is that my `f` is a `M[A] => M[B]`: I don't see anything in scalaz that can help with that (I only see things like `A => M[B]`, `M[A => B]` etc)
oxbow_lakes
`val f: List[A] => List[B] = ...; (grouped map f join): List[B]`
retronym