2012-06-21 10 views
5

Tengo un List[Option[MyClass]] con None en posiciones aleatorias y necesito 'llenar' esa lista nuevamente, desde un List[MyClass], manteniendo el orden.Cómo reemplazar (llenar) Ninguna entrada en la Lista de opciones de otra lista usando Scala idiomático?

Aquí están las listas de muestra y resultado esperado:

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)) 

Entonces, ¿cómo habría una Scala idiomática para procesar esa lista?

Respuesta

13
def fillL[T](a:List[Option[T]], b:List[T]) = { 
    val iterB = b.iterator 
    a.map(_.orElse(Some(iterB.next))) 
} 
1

La solución iterador es sin duda idiomática Scala, y sin duda es concisa y fácil de entender, pero no es funcional tiempo -cualquier se llama next en un iterador que está firmemente en la tierra de los efectos secundarios.

Un enfoque más funcional sería el uso de un pliegue:

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 

Aquí nos movemos a través de la lista de gappy manteniendo al mismo tiempo otras dos listas: una para los artículos que hemos procesado, y el otro para el resto elementos de relleno

Este tipo de solución no es necesariamente mejor que el otro: Scala está diseñado para permitirle mezclar construcciones funcionales e imperativas de esa manera, pero tiene ventajas potenciales.

+0

"cada vez que llamas a continuación en un iterador estás firmemente en la tierra de los efectos secundarios". Es cierto, pero en este caso están perfectamente encapsulados en el método, que permanece referencialmente transparente. –

+0

@Paul: Correcto, creo que la otra solución es excelente, y es el enfoque que elegiría para resolver este problema en mi propio código. Pero involucra efectos secundarios, y en algunas situaciones similares que pueden no ser ideales. –

0

que acababa de escribir de la manera directa, a juego en la cabeza de las listas y gastos de cada caso apropiadamente:

def fill[A](l1: List[Option[A]], l2: List[A]) = (l1, l2) match { 
    case (Nil, _) => Nil 
    case (_, Nil) => l1 
    case (Some(x) :: xs, _) => Some(x) :: fill(xs, l2) 
    case (None :: xs, y :: ys) => Some(y) :: fill(xs, ys) 
} 

Es de suponer que una vez que se quedará sin cosas para llenarla de, que acaba de salir el resto de los None s allí.

Cuestiones relacionadas