A library that makes some Scala 2.13 APIs available on Scala 2.11 and 2.12, facilitating cross-building Scala 2.13 and 3.0 code on older versions
—
Enhanced collection operations including safe min/max methods, advanced transformations, and functional programming utilities.
implicit class TraversableOnceExtensionMethods[A](private val self: TraversableOnce[A])
extends AnyVal {
def minOption[B >: A](implicit ord: Ordering[B]): Option[A]
def maxOption[B >: A](implicit ord: Ordering[B]): Option[A]
def minByOption[B](f: A => B)(implicit cmp: Ordering[B]): Option[A]
def maxByOption[B](f: A => B)(implicit cmp: Ordering[B]): Option[A]
}Safe versions of min/max operations that return Option instead of throwing exceptions on empty collections.
def minOption[B >: A](implicit ord: Ordering[B]): Option[A]
def maxOption[B >: A](implicit ord: Ordering[B]): Option[A]Find the minimum or maximum element in a collection.
Returns:
Some(element) if the collection is non-emptyNone if the collection is emptyUsage:
List(3, 1, 4, 1, 5).minOption // Some(1)
List(3, 1, 4, 1, 5).maxOption // Some(5)
List.empty[Int].minOption // None
List.empty[Int].maxOption // Nonedef minByOption[B](f: A => B)(implicit cmp: Ordering[B]): Option[A]
def maxByOption[B](f: A => B)(implicit cmp: Ordering[B]): Option[A]Find the element that produces the minimum or maximum value when the function is applied.
Usage:
case class Person(name: String, age: Int)
val people = List(Person("Alice", 25), Person("Bob", 30), Person("Charlie", 20))
people.minByOption(_.age) // Some(Person("Charlie", 20))
people.maxByOption(_.age) // Some(Person("Bob", 30))
List.empty[Person].minByOption(_.age) // Noneimplicit class TraversableLikeExtensionMethods[A, Repr](
private val self: GenTraversableLike[A, Repr]) extends AnyVal {
def tapEach[U](f: A => U)(implicit bf: CanBuildFrom[Repr, A, Repr]): Repr
def partitionMap[A1, A2, That, Repr1, Repr2](f: A => Either[A1, A2]): (Repr1, Repr2)
def groupMap[K, B, That](key: A => K)(f: A => B): Map[K, That]
def groupMapReduce[K, B](key: A => K)(f: A => B)(reduce: (B, B) => B): Map[K, B]
def distinctBy[B, That](f: A => B): That
}def tapEach[U](f: A => U)(implicit bf: CanBuildFrom[Repr, A, Repr]): ReprApply a function to each element for its side effects and return the original collection unchanged.
Usage:
List(1, 2, 3)
.tapEach(println) // prints 1, 2, 3
.map(_ * 2) // List(2, 4, 6)def partitionMap[A1, A2, That, Repr1, Repr2](f: A => Either[A1, A2]): (Repr1, Repr2)Partition a collection into two collections based on a function that returns Either.
Usage:
val numbers = List(1, 2, 3, 4, 5, 6)
val (evens, odds) = numbers.partitionMap { n =>
if (n % 2 == 0) Left(n) else Right(n)
}
// evens: List(2, 4, 6)
// odds: List(1, 3, 5)def groupMap[K, B, That](key: A => K)(f: A => B): Map[K, That]Group elements by a key function and transform them with a mapping function in one operation.
Usage:
case class Student(name: String, grade: Char, score: Int)
val students = List(
Student("Alice", 'A', 95),
Student("Bob", 'B', 85),
Student("Charlie", 'A', 92)
)
val scoresByGrade = students.groupMap(_.grade)(_.score)
// Map('A' -> List(95, 92), 'B' -> List(85))def groupMapReduce[K, B](key: A => K)(f: A => B)(reduce: (B, B) => B): Map[K, B]Group elements by a key, transform them, and reduce the values in each group.
Usage:
val students = List(
Student("Alice", 'A', 95),
Student("Bob", 'B', 85),
Student("Charlie", 'A', 92)
)
val avgScoreByGrade = students.groupMapReduce(_.grade)(_.score)(_ + _)
// Map('A' -> 187, 'B' -> 85) // Note: sum, not averagedef distinctBy[B, That](f: A => B): ThatRemove duplicate elements based on the result of a key function.
Usage:
case class Person(name: String, age: Int)
val people = List(
Person("Alice", 25),
Person("Bob", 30),
Person("Alice", 26) // duplicate name
)
val uniqueByName = people.distinctBy(_.name)
// List(Person("Alice", 25), Person("Bob", 30))class SizeCompareOps(private val it: Traversable[_]) extends AnyVal {
def <(size: Int): Boolean
def <=(size: Int): Boolean
def ==(size: Int): Boolean
def !=(size: Int): Boolean
def >=(size: Int): Boolean
def >(size: Int): Boolean
}Efficient size comparison operations that can short-circuit for better performance with large collections.
Usage:
val list = List(1, 2, 3, 4, 5)
// Size comparisons
list.sizeIs < 10 // true
list.sizeIs >= 5 // true
list.sizeIs == 5 // true
list.sizeIs != 3 // true
// Sequence length comparisons
val seq = Seq(1, 2, 3)
seq.lengthIs > 2 // true
seq.lengthIs <= 5 // trueimplicit class TraversableExtensionMethods[A](private val self: Traversable[A])
extends AnyVal {
def iterableFactory: GenericCompanion[Traversable]
def sizeCompare(otherSize: Int): Int
def sizeIs: SizeCompareOps
def sizeCompare(that: Traversable[_]): Int
}def sizeCompare(otherSize: Int): Int
def sizeCompare(that: Traversable[_]): IntCompare the size of a collection with an integer or another collection efficiently.
Returns:
Usage:
val list1 = List(1, 2, 3)
val list2 = List(4, 5)
list1.sizeCompare(5) // negative (3 < 5)
list1.sizeCompare(3) // zero (3 == 3)
list1.sizeCompare(list2) // positive (3 > 2)implicit class SeqExtensionMethods[A](private val self: Seq[A]) extends AnyVal {
def lengthIs: SizeCompareOps
}Size comparison operations specifically for sequences.
import scala.collection.compat._
case class Sale(product: String, amount: Double, region: String)
val sales = List(
Sale("laptop", 999.99, "north"),
Sale("mouse", 29.99, "south"),
Sale("laptop", 899.99, "north"),
Sale("keyboard", 79.99, "south")
)
// Safe aggregations
val maxSale = sales.maxByOption(_.amount) // Some(Sale("laptop", 999.99, "north"))
val minSale = sales.minByOption(_.amount) // Some(Sale("mouse", 29.99, "south"))
// Group and aggregate
val totalByRegion = sales.groupMapReduce(_.region)(_.amount)(_ + _)
// Map("north" -> 1899.98, "south" -> 109.98)
// Unique products by region
val productsByRegion = sales.groupMap(_.region)(_.product)
.view.mapValues(_.distinctBy(identity)).toMap
// Process with side effects
val processedSales = sales
.tapEach(sale => println(s"Processing ${sale.product}"))
.filter(_.amount > 50)def processNumbers(numbers: List[Int]): Map[String, List[Int]] = {
numbers
.tapEach(n => if (n < 0) println(s"Warning: negative number $n"))
.partitionMap { n =>
if (n % 2 == 0) Left(("even", n)) else Right(("odd", n))
} match {
case (evens, odds) =>
Map("even" -> evens.map(_._2), "odd" -> odds.map(_._2))
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-scala-lang-modules--scala-collection-compat