0xDEADBEEF

[RSS]
««« »»»

Novinky kolekcí ve Scale 2.13

11. 10. 2018

Nad­chá­ze­jící verze Scaly 2.13 při­nese jednu velkou změnu: Nový fra­mework ko­lekcí. Došlo k jejich in­ter­nímu pře­ko­pání, zjed­no­du­šení a cel­ko­vému uhla­zení (ko­nečně funkční me­cha­nis­mus po­hledů). Velká část z těchto změn by měla být in­terní zá­le­ži­tostí. Nové ko­lekce sice ne­bu­dou bi­nárně kom­pa­ti­bilní s těmi ve verzi 2.12 (zmizí na­pří­klad (ne)ob­lí­bený hla­vo­lam CanBuildFrom). Bude třeba pře­kom­pi­lo­vat, ale na úrovni zdro­jo­vých textů by kom­pa­ti­bi­lita měla být z velké části za­cho­vána.

Kromě toho, ale při­bylo ně­ko­lik metod, které mi vždycky chy­běly a musel jsem je ti­síc­krát ob­chá­zet a na­hra­zo­vat. Tady je seznam těch, které jsem ob­je­vil.

In place ope­race nad mě­ni­tel­nými ko­lek­cemi

O řazení na místě se stará scala.util.Sorting.stableSort, který in­terně po­u­žívá buď java.util.Arrays.sort nebo, pokud po­u­ží­vám vlastní Ordering, merge sort. To je malý ne­do­sta­tek, pro­tože merge sort po­tře­buje alo­ko­vat po­mocné pole a není tedy úplně in place.

Vy­lep­šené groupBy metody:

def groupMap[K, B](key: A => K)(f: A => B): immutable.Map[K, Seq[B]]
def groupMapReduce[K, B](key: A => K)(f: AB)(reduce: (B, B) ⇒ B): immutable.Map[K, B]

groupMap je přesně to, co mi chy­bělo. Ná­sle­du­jící dva řádky mají iden­tické cho­vání.

xs.groupMap(key)(f)
xs.groupBy(key).map { case (k, vs) => (k, vs.map(f)) }

Je to jednak kratší a navíc nejsou třeba alo­kace do­čas­ných ko­lekcí.

xs.groupMapReduce(keyF)(mapF)(redF)
xs.groupBy(keyF).map { case (k, vs) => vs.map(mapF).reduce(redF) }

collect­First

collect je uži­tečná metoda, která kom­bi­nuje mapfilter. Jako ar­gu­ment se ji předá par­ci­ální funkce, ele­menty, pro které je de­fi­no­vaná budou za­cho­vány a trans­for­mo­vány. Ná­sle­du­jící dva řádky se cho­vají iden­ticky:

xs.collect { case x if f(x) => g(x) }
xs.filter(f).map(g)

Není třeba vy­tvá­řet ko­lekci me­zi­vý­sledku + par­ci­ální funkce nemusí ob­sa­ho­vat jen jeden pre­di­kát, ale li­bo­volný pat­tern matching (ide­ální na­pří­klad pro regexy)

Pro sou­měr­nost při­byla collectFirst, které fun­guje jako find po níž ná­sle­duje map.

Bez­pečná maxima a minima

Dřívě exis­to­valy jednak metody headlast, které pro prázd­nou ko­lekci vy­ho­dily vý­jimku a pak bez­pečné metody headOptionlastOption, ale pro zís­kání minim a maximu exis­to­valy jen vý­jimky há­ze­jící verze. Ve verzi 2.13 bude tento ne­do­sta­tek na­pra­ven a při­bu­dou metody maxOption, minOption, maxByOption, minByOption.

V po­dob­ném duchu se nesou nové metody par­su­jící string na čísla: toInt při­bude bez­pečný brat­ří­ček toIntOption. Možná jde o drob­nosti, ale na druhou stranu vy­pl­ňují mezery v or­to­go­na­litě.

Různé uži­tečné drob­nosti

xs.distinctBy(f)

// je identické jako

val ys = xs.reverse.map { x => (f(x), x) }.toMap.values.toSet
xs.filter(ys)
xs.partitionWith(f)

// stejné jako

val ys = xs.map(f)
val ls = ys.collect { case Left(l) => l }
val rs = ys.collect { case Right(r) => r }
(ls, rs)

Nové datové struk­tury

To jsou ně­které za­jí­mavé změny, které při­jdou. Scala 2.13 je zase jedna verze, která po dlouhé době vypadá za­jí­mavě.


Do­da­tek: Pořád mi chybí metoda top(k), která by vrá­tila k nej­vět­ších ele­mentů (a její va­ri­anty topkBy(k, f) atd). Nej­po­ho­dl­něji se to samé dá za­ří­dit pomocí xs.sortBy(f).take(10), ale jde o ne­op­ti­mální řešení s kom­ple­xi­tou O(n log(n)). To samé se dá za­ří­dit přes haldu nebo quick­se­lect v čase O(n log(k)), ale musím všechno napsat sám.

píše k47 (@kaja47, k47)