Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to replace(fill) None entries on List of Options from another List using idiomatic Scala?

Tags:

idioms

list

scala

I have a List[Option[MyClass]] with None in random positions and I need to 'fill' that list again, from a List[MyClass], maintaining the order.

Here are sample lists and expected result:

val listA = List(Some(3),None,Some(5),None,None)
val listB = List(7,8,9)
val expectedList = List(Some(3), Some(7), Some(5), Some(8), Some(9))

So, how would be a idiomatic Scala to process that list?

like image 997
Johnny Everson Avatar asked Jun 21 '12 13:06

Johnny Everson


2 Answers

def fillL[T](a:List[Option[T]], b:List[T]) = {
    val iterB = b.iterator
    a.map(_.orElse(Some(iterB.next)))
}
like image 177
xiefei Avatar answered Sep 29 '22 01:09

xiefei


The iterator solution is arguably idiomatic Scala, and is definitely concise and easy to understand, but it's not functional—any time you call next on an iterator you're firmly in the land of side effects.

A more functional approach would be to use a fold:

def fillGaps[A](gappy: List[Option[A]], filler: List[A]) =
  gappy.foldLeft((List.empty[Option[A]], filler)) {
    case ((current, fs), Some(item)) => (current :+ Some(item), fs)
    case ((current, f :: fs), None) => (current :+ Some(f), fs)
    case ((current, Nil), None) => (current :+ None, Nil)
  }._1

Here we move through the gappy list while maintaining two other lists: one for the items we've processed, and the other for the remaining filler elements.

This kind of solution isn't necessarily better than the other—Scala is designed to allow you to mix functional and imperative constructions in that way—but it does have potential advantages.

like image 20
Travis Brown Avatar answered Sep 28 '22 23:09

Travis Brown