user180940
user180940

Reputation: 354

How can I functionally iterate over a collection combining elements?

I have a sequence of values of type A that I want to transform to a sequence of type B.

Some of the elements with type A can be converted to a B, however some other elements need to be combined with the immediately previous element to produce a B.

I see it as a small state machine with two states, the first one handling the transformation from A to B when just the current A is needed, or saving A if the next row is needed and going to the second state; the second state combining the saved A with the new A to produce a B and then go back to state 1.

I'm trying to use scalaz's Iteratees but I fear I'm overcomplicating it, and I'm forced to return a dummy B when the input has reached EOF.

What's the most elegant solution to do it?

Upvotes: 0

Views: 340

Answers (2)

jwvh
jwvh

Reputation: 51271

What about invoking the sliding() method on your sequence?

You might have to put a dummy element at the head of the sequence so that the first element (the real head) is evaluated/converted correctly.

If you map() over the result from sliding(2) then map will "see" every element with its predecessor.

val input:  Seq[A] = ??? // real data here (no dummy values)
val output: Seq[B] = (dummy +: input).sliding(2).flatMap(a2b).toSeq
def a2b( arg: Seq[A] ): Seq[B] = {
    // arg holds 2 elements
    // return a Seq() of zero or more elements
}

Upvotes: 2

nattyddubbs
nattyddubbs

Reputation: 2095

Taking a stab at it:

Partition your list into two lists. The first is the one you can directly convert and the second is the one that you need to merge.

scala> val l = List("String", 1, 4, "Hello")
l: List[Any] = List(String, 1, 4, Hello)

scala> val (string, int) = l partition { case s:String => true case _ => false}
string: List[Any] = List(String, Hello)
int: List[Any] = List(1, 4)

Replace the logic in the partition block with whatever you need.

After you have the two lists, you can do whatever you need to with your second using something like this

scala> string ::: int.collect{case i:Integer => i}.sliding(2).collect{ 
     | case List(a, b) => a+b.toString}.toList
res4: List[Any] = List(String, Hello, 14)

You would replace the addition with whatever your aggregate function is.

Hopefully this is helpful.

Upvotes: 0

Related Questions