2012-06-21 6 views
5

Ho un List[Option[MyClass]] con None in posizioni casuali e ho bisogno di "riempire" di nuovo quell'elenco, da un List[MyClass], mantenendo l'ordine.Come sostituire (compilare) Nessuna voce su Elenco di opzioni da un altro elenco utilizzando la Scala idiomatica?

Qui sono gli elenchi di esempio e risultato atteso:

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

Così, come sarebbe una Scala idiomatica per elaborare quella lista?

risposta

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

La soluzione iteratore è senza dubbio idiomatica Scala, ed è sicuramente conciso e di facile comprensione, ma non è funzionale tempo -Qualsiasi si chiama next su un iteratore si è saldamente nella terra di effetti collaterali.

Un approccio più funzionale sarebbe quella di utilizzare una piega:

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 

Qui ci muoviamo attraverso la lista gappy, pur mantenendo le altre due liste: una per le voci che abbiamo elaborato, e l'altro per il restante elementi di riempimento.

Questo tipo di soluzione non è necessariamente migliore dell'altro: Scala è progettato per consentire di combinare costruzioni funzionali e imperative in questo modo, ma presenta potenziali vantaggi.

+0

"ogni volta che si chiama su un iteratore, si è fermamente nella terra degli effetti collaterali". È vero, ma in questo caso sono perfettamente incorporati nel metodo, che rimane referenzialmente trasparente. –

+0

@Paul: Giusto, penso che l'altra soluzione sia ottima, ed è l'approccio che sceglierei per risolvere questo problema nel mio codice. Ma coinvolge effetti collaterali e in alcune situazioni simili che potrebbero non essere ideali. –

0

avevo appena scrivo in modo diretto, corrispondenti sulle teste delle liste e la gestione caso per caso in modo appropriato:

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

Presumibilmente, una volta che si esaurisca di cose da riempire con, te ne vai il resto del None s in là.

Problemi correlati