32 - collect

Láttuk most már a PartialFunction traitet. Ezzel kapcsolatos a kollekciók által támogatott collect metódus, pl. a List[T]-belinek a szignatúrája:

1
def collect[U]( pf: PartialFunction[T,U] ): List[U]

A metódus alkalmazza a pf parciális függvényt azokra az elemekre, melyeken definiált, és az eredményekből épít egy listát.

Fejezzük ezt ki a már ismert kollekcióműveletekkel!

1
list.collect( pf ) == list.filter( pf.isDefinedAt(_) ).map( pf )

Válasz mutatása

partial function példányosítása

Természetesen lehet PartialFunctiont úgy is példányosítani, ahogy traiteket szoktunk: le lehet belőle származtatni egy osztályt, implementálni benne ezt a két metódust. De van rá nyelvi szinten kényelmes megoldás is, mégpedig ugyanaz, mint amit már match kifejezések belsejében láttunk:

1
2
3
val isEven: PartialFunction[Int, String] = {
  case x if x%2 == 0 => s"$x is even"
}

Mit látunk ebből a kódból?

  • kapcsos zárójelben, case-ek felsorolásával deklarálhatunk parciális függvényt
  • ebből az isDefinedAt(x) metódus úgy lesz implementálva, hogy megnézi, az x argumentumra van-e illeszkedő case; ha van, akkor isDefinedAt true lesz, különben false (a case jobb oldalán álló kifejezést nem értékeli ekkor ki!)
  • az apply(x) pedig matcheli x-et erre a blokkra. (Ha nem illeszkedik egy case sem az inputra, azaz ha erre az inputra isDefinedAt(x) hamis, akkor MatchErrort dob.)

Mi lesz tehát pl. List(1,4,2,8,5,7).collect( isEven ) értéke?

1
List("4 is even","2 is even","8 is even")

Válasz mutatása

Írjunk olyan függvényt, ami egy List[Pet]-ből kigyűjti a listában szereplő macskák neveit!

1
2
3
4
5
6
def macsNevList( petList: List[Pet] ) =
  petList collect { case m:Cat => m.name }

//teszteljük
val petList = List( Cat("Nyuszi"), Cat("Morcos"), Dog("Freya"), Cat("Omega"))
println( macsNevList(petList) ) //prints List(Nyuszi, Morcos, Omega)
Válasz mutatása

Láthatjuk: abból, hogy a petListen hívjuk a collect metódust, ebből a Scala fordító kitalálja, hogy a PartialFunction[K,V]-ben a K mondjuk Pet; a kimeneti típust pedig onnan tudja, hogy az egyetlen esetünk bal oldalán a minta azt mondju, hogy m egy Cat, akkor a jobb oldalán m.name, a macska neve pedig String lesz, és ezért akkor egy PartialFunction[Pet,String] az, amit létrehozunk a collect-ben.

A minta persze pontosan a macskákra fog illeszkedni, akiknek a neveit össze tudjuk szedni.


Utolsó frissítés: 2020-12-25 22:14:32