0xDEADBEEF

RSS
««« »»»

Novinky kolekcí ve Scale 2.13

11. 10. 2018

Nadcházející verze Scaly 2.13 přinese jednu velkou změnu: Nový framework kolekcí. Došlo k jejich internímu překopání, zjednodušení a celkovému uhlazení (konečně funkční mechanismus pohledů). Velká část z těchto změn by měla být interní záležitostí. Nové kolekce sice nebudou binárně kompatibilní s těmi ve verzi 2.12 (zmizí například (ne)oblíbený hlavolam CanBuildFrom). Bude třeba překompilovat, ale na úrovni zdrojových textů by kompatibilita měla být z velké části zachována.

Kromě toho, ale přibylo několik metod, které mi vždycky chyběly a musel jsem je tisíckrát obcházet a nahrazovat. Tady je seznam těch, které jsem objevil.

In place operace nad měnitelnými kolekcemi

O řazení na místě se stará scala.util.Sorting.stableSort, který interně používá buď java.util.Arrays.sort nebo, pokud používám vlastní Ordering, merge sort. To je malý nedostatek, protože merge sort potřebuje alokovat pomocné pole a není tedy úplně in place.

Vylepš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: A ⇒ B)(reduce: (B, B) ⇒ B): immutable.Map[K, B]

groupMap je přesně to, co mi chybělo. Následující dva řádky mají identické chová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 alokace dočasných kolekcí.

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

collectFirst

collect je užitečná metoda, která kombinuje map a filter. Jako argument se ji předá parciální funkce, elementy, pro které je definovaná budou zachovány a transformovány. Následující dva řádky se chovají identicky:

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

Není třeba vytvářet kolekci mezivýsledku + parciální funkce nemusí obsahovat jen jeden predikát, ale libovolný pattern matching (ideální například pro regexy)

Pro souměrnost přibyla collectFirst, které funguje jako find po níž následuje map.

Bezpečná maxima a minima

Dřívě existovaly jednak metody head a last, které pro prázdnou kolekci vyhodily výjimku a pak bezpečné metody headOption a lastOption, ale pro získání minim a maximu existovaly jen výjimky házející verze. Ve verzi 2.13 bude tento nedostatek napraven a přibudou metody maxOption, minOption, maxByOption, minByOption.

V podobném duchu se nesou nové metody parsující string na čísla: toInt přibude bezpečný bratříček toIntOption. Možná jde o drobnosti, ale na druhou stranu vyplňují mezery v ortogonalitě.

Různé užitečné drobnosti

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é struktury

To jsou některé zajímavé změny, které přijdou. Scala 2.13 je zase jedna verze, která po dlouhé době vypadá zajímavě.


Dodatek: Pořád mi chybí metoda top(k), která by vrátila k největších elementů (a její varianty topkBy(k, f) atd). Nejpohodlněji se to samé dá zařídit pomocí xs.sortBy(f).take(10), ale jde o neoptimální řešení s komplexitou O(n log(n)). To samé se dá zařídit přes haldu nebo quickselect v čase O(n log(k)), ale musím všechno napsat sám.

píše k47 (@kaja47)