2015-11-09 11 views
6

Mam zagnieżdżonej struktury case klas w Listusunąć elementy z listy struktury klasowej przypadek sprawnie i elegancko

dla uproszczenia będziemy używać następujących jako przykład -

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

powiedzieć, że jest List[Department]; teraz jeśli chcę utworzyć nowy List[Department] przez filtrowanie Address dla każdego Person, który nie ma określonej wartości zipCode; Tradycyjnie można wykonać następujące

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

to podejście nie jest wydajnych w zależności od poziomu zagnieżdżenia może być w konfiguracji Big O (N^2) lub Big O (n^3);

Próbuję nauczyć się soczewek za pomocą Monocle. Do tej pory nauczyłem się, że soczewki są użyteczne, gdy trzeba "zmodyfikować" głęboko zagnieżdżoną strukturę klasową, ale nie znalazły jeszcze sposobu na "odcięcie" określonej części zagnieżdżonej struktury na podstawie warunku i zwrócenie nowej struktury . Czy to możliwe za pośrednictwem Monocle? Również nie jestem pewien, czy soczewki będą w stanie pomóc w osiągnięciu lepszego czasu Big O?

+1

Podany w celu ustalenia, czy departamenty powinny znajdować się w nowym dept, trzeba spojrzeć na wszystkie adresy wszystkich osób, wtedy nie widzę, jak może to być tylko O ​​(#d * #p * #a) . –

+0

@AArchetypalPaul: nie zgadzam się z twoim komentarzem. To może pomijać "sprawną" część pytania; wciąż szuka eleganckiego sposobu, aby to zrobić, aby sprawdzić, czy soczewki/monokl mogą w tym pomóc. czy wiesz? –

+0

Przeczytaj o koncepcji o nazwie "Obiektywy". Niektóre biblioteki, takie jak Monocle/scalaz, implementują je. – Maxim

Odpowiedz

3

Poniżej jest zasadniczo równoważny do realizacji pod względem wydajności, ale to arguable wyraźniej:

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

To właśnie buduje przechodzenie aby przejść do listy każdej osoby adresów, dzięki czemu można go zmodyfikować w oparciu o predykat. Nie jestem pewien, czy istnieje lepszy sposób na filtrowanie (ponieważ kody pocztowe nie służą jako unikalne wskaźniki), ale może Julien zważy na nie jeden.

Powiązane problemy