Question

I have a collection which I want to map to a new collection, however each resulting value is dependent on the value before it in some way.I could solve this with a leftFold

val result:List[B] = (myList:List[A]).foldLeft(C -> List.empty[B]){ 
  case ((c, list), a) =>
    ..some function returning something like..
    C -> (B :: list)
} 

The problem here is I need to iterate through the entire list to retrieve the resultant list. Say I wanted a function that maps TraversableOnce[A] to TraversableOnce[B] and only evaluate members as I call them? It seems to me to be a fairly conventional problem so Im wondering if there is a common approach to this. What I currently have is:

implicit class TraversableOnceEx[T](val self : TraversableOnce[T]) extends AnyVal {

   def foldyMappyFunction[A, U](a:A)(func:(A,T) => (A,U)):TraversableOnce[U] = {
     var currentA = a
     self.map { t =>
        val result = func(currentA, t)
        currentA = result._1
        result._2
     }
   } 
}

As far as functional purity goes, you couldn't run it in parallel, but otherwise it seems sound.

An example would be; Return me each element and if it is the first time that element has appeared before.

val elements:TraversableOnce[E]
val result = elements.mappyFoldyFunction(Set.empty[E]) {
 (s, e) => (s + e) -> (e -> s.contains(e))
}
result:TraversableOnce[(E,Boolean)]
Was it helpful?

Solution

You might be able to make use of the State Monad. Here is your example re-written using scalaz:

import scalaz._, Scalaz._

def foldyMappy(i: Int) = State[Set[Int], (Int, Boolean)](s => (s + i, (i, s contains(i))))

val r = List(1, 2, 3, 3, 6).traverseS(foldyMappy)(Set.empty[Int])._2

//List((1,false), (2,false), (3,false), (3,true), (6,false))
println(r)

OTHER TIPS

It is look like you need SeqView. Use view or view(from: Int, until: Int) methods for create a non-strict view of list.

I really don't understand your example as your contains check will always result to false.

foldLeft is different. It will result in a single value by aggregating all elements of the list. You clearly need map (List => List).

Anyway, answering your question about laziness: you should use Stream instead of List. Stream doesn't evaluate the tail before actually calling it.

Stream API

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top