2015-11-09 8 views
6

Ho un nidificata struttura case classi in un Listrimuovere elementi da un elenco di struttura case classe efficiente ed elegantemente

per semplicità utilizzerà segue come esempio -

case class Address(street: String, city: String, state: String, zipCode: Int) 
case class Person(firstName: String, lastName: String, addresses: List[Address]) 
case class Department(people: List[Person]) 

dire c'è List[Department]; ora se voglio creare un nuovo List[Department] filtrando Address per ogni Person che non ha un valore specifico zipCode; tradizionalmente possiamo fare seguente

def filterPersonsByAddress(dlist: List[Department]): List[Department] = { 
    dlist.map { d => 
    val people = d.people.map { p => 
     p.copy(addresses = p.addresses.filterNot(_.zipCode == 38978))} 
     d.copy(people=people) 
    } 
} 

Questo approccio non è performante come a seconda del livello di nidificazione può essere Big O (n^2) o Big O (n^3);

Sto cercando di apprendere le lenti tramite Monocle. Finora ciò che ho imparato è che le lenti sono utili quando devi "modificare" una struttura di classe case profondamente annidata ma non hai ancora trovato un modo per "tagliare" parte della struttura nidificata in base a una condizione e restituire una nuova struttura . È possibile per via Monocle? Inoltre, non sono sicuro che le lenti saranno in grado di aiutare a raggiungere un tempo di Big O migliore?

+1

Dato per determinare se i reparti devono essere nel nuovo reparto, è necessario esaminare tutti gli indirizzi di tutte le persone, quindi non vedo come può essere qualsiasi cosa tranne O (#d * #p * #a) . –

+0

@TheArchetypalPaul: non è in disaccordo con il tuo commento. Ciò potrebbe tralasciare una parte "efficiente" della domanda; ancora alla ricerca di un modo elegante per fare questo per vedere se le lenti/Monocle possono aiutare lì. lo sai? –

+0

Leggi il concetto chiamato "Lenti". Alcune librerie come Monocle/scalaz lo implementano. – Maxim

risposta

3

Il seguente è sostanzialmente equivalente a l'implementazione in termini di prestazioni, ma è discutibile più chiaro:

import monocle.Traversal, monocle.macros.GenLens 
import monocle.function.all._, monocle.std.list._ 

val deptAddresses: Traversal[Department, List[Address]] = 
    GenLens[Department](_.people) 
    .composeTraversal(each) 
    .composeLens(GenLens[Person](_.addresses)) 

val filterAddresses: Department => Department = 
    deptAddresses.modify(_.filterNot(_.zipCode == 38978)) 

Si costruisce solo un attraversamento per navigare alla lista di ogni persona di indirizzi in modo che sia possibile modificarlo sulla base di il predicato. Non sono sicuro che esista un modo migliore per eseguire il filtraggio (dato che i codici postali non servono come indici unici), ma forse Julien ne valuterà uno.