Idiomatic map combined with fold


I’m trying to traverse a sequence, mapping each element into a new sequence, but with a stateful context that affects how each element is mapped.

Think of .map mixed with .foldLeft, or scanLeft.

.scanLeft isn’t quite what I want, because ultimately I don’t want the folded state, I want the mapped elements.

I could just hack and close over mutable state when I call .map, but that is a bit icky.

I could write my own recursive decomposition of the sequence, and pass the state as an extra parameter, but construction of the resulting sequence means either doing a reverse order buildup or efficient appending to allow tail-recursion, or have a potentially large stack as recursion unfolds, or a continuation to build the sequence by prepending.

I could munge the output sequence in with the state as a pair and use .foldLeft.

I could use Iterable.unfold and again use a pair of the ‘real’ state and the output sequence being built up.

None of these seem quite right to me, although push come to shove, I’ll just do the hack if that’s what’s needed, or use a sequence type that supports efficient appending.

Just curious to know if there is a more idiomatic way of doing this, this comes up every now and then…

If you have cats in scope this is just mapAccumulate
I also once proposed this to be added to the stdlib: Add mapWithState · Issue #122 · scala/scala-library-next · GitHub

Thanks @BalmungSan. I’ll give the Cats Traverse based solution a whirl, I presume you meant that one. Have added my vote to your GitHib issue too.

Ironically once I searched for mapAccumulate I found a very similar issue already raised in Scala Users. :grinning:

1 Like