Enhanced methods for existing Scala collections including safe operations, size comparisons, and functional utilities. These extensions provide Scala 2.13-style APIs on older Scala versions through implicit conversions.
Safe minimum and maximum operations that return Option instead of throwing exceptions on empty collections.
/**
* Returns the minimum element as an Option, or None if empty
* @param ord Ordering for elements
* @return Some(minimum) or None if collection is empty
*/
def minOption[B >: A](implicit ord: Ordering[B]): Option[A]
/**
* Returns the maximum element as an Option, or None if empty
* @param ord Ordering for elements
* @return Some(maximum) or None if collection is empty
*/
def maxOption[B >: A](implicit ord: Ordering[B]): Option[A]
/**
* Returns the minimum element by function as an Option
* @param f Function to extract comparison key
* @param cmp Ordering for comparison keys
* @return Some(minimum) or None if collection is empty
*/
def minByOption[B](f: A => B)(implicit cmp: Ordering[B]): Option[A]
/**
* Returns the maximum element by function as an Option
* @param f Function to extract comparison key
* @param cmp Ordering for comparison keys
* @return Some(maximum) or None if collection is empty
*/
def maxByOption[B](f: A => B)(implicit cmp: Ordering[B]): Option[A]Usage Examples:
import scala.collection.compat._
val numbers = List(3, 1, 4, 1, 5)
val empty = List.empty[Int]
numbers.minOption // Some(1)
numbers.maxOption // Some(5)
empty.minOption // None
empty.maxOption // None
// Min/max by function
case class Person(name: String, age: Int)
val people = List(Person("Alice", 25), Person("Bob", 30))
people.minByOption(_.age) // Some(Person("Alice", 25))
people.maxByOption(_.age) // Some(Person("Bob", 30))Efficient size comparison methods that can short-circuit evaluation for large collections.
/**
* Compare collection size with an integer
* @param otherSize Size to compare against
* @return Negative if smaller, 0 if equal, positive if larger
*/
def sizeCompare(otherSize: Int): Int
/**
* Compare collection size with another collection
* @param that Collection to compare size against
* @return Negative if smaller, 0 if equal, positive if larger
*/
def sizeCompare(that: Traversable[_]): Int
/**
* Get size comparison operations object
* @return SizeCompareOps for fluent size testing
*/
def sizeIs: SizeCompareOps
class SizeCompareOps {
def <(size: Int): Boolean
def <=(size: Int): Boolean
def ==(size: Int): Boolean
def !=(size: Int): Boolean
def >=(size: Int): Boolean
def >(size: Int): Boolean
}Usage Examples:
import scala.collection.compat._
val data = List(1, 2, 3, 4, 5)
// Direct size comparison
data.sizeCompare(3) // Positive (> 0)
data.sizeCompare(5) // 0 (equal)
data.sizeCompare(10) // Negative (< 0)
// Fluent size testing
if (data.sizeIs > 3) println("Large collection")
if (data.sizeIs <= 10) println("Manageable size")
// Efficient for lazy collections
val stream = Stream.from(1)
if (stream.sizeIs > 100) println("This won't evaluate the entire stream")Advanced functional operations including grouping, partitioning, and deduplication.
/**
* Remove duplicate elements based on a key function
* @param f Function to extract comparison key
* @param cbf CanBuildFrom for result collection
* @return Collection with duplicates removed
*/
def distinctBy[B, That](f: A => B)(implicit cbf: CanBuildFrom[Repr, A, That]): That
/**
* Group elements by key and transform values in one operation
* @param key Function to extract grouping key
* @param f Function to transform values
* @param bf CanBuildFrom for value collections
* @return Map of grouped and transformed values
*/
def groupMap[K, B, That](key: A => K)(f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): Map[K, That]
/**
* Group elements by key, transform values, and reduce to single value per group
* @param key Function to extract grouping key
* @param f Function to transform values
* @param reduce Function to reduce multiple values to one
* @return Map with single reduced value per group
*/
def groupMapReduce[K, B](key: A => K)(f: A => B)(reduce: (B, B) => B): Map[K, B]
/**
* Partition elements and transform them simultaneously
* @param f Function returning Either for partitioning and transformation
* @param bf1 CanBuildFrom for left partition
* @param bf2 CanBuildFrom for right partition
* @return Tuple of (left partition, right partition)
*/
def partitionMap[A1, A2, That, Repr1, Repr2](f: A => Either[A1, A2])(implicit bf1: CanBuildFrom[Repr, A1, Repr1], bf2: CanBuildFrom[Repr, A2, Repr2]): (Repr1, Repr2)Usage Examples:
import scala.collection.compat._
val people = List("Alice", "Bob", "Alice", "Charlie", "Bob")
// Remove duplicates by function
people.distinctBy(_.length) // List("Alice", "Bob")
// Group and map in one operation
val words = List("apple", "apricot", "banana", "blueberry")
words.groupMap(_.head.toUpper)(_.length)
// Map('A' -> List(5, 7), 'B' -> List(6, 9))
// Group, map and reduce
words.groupMapReduce(_.head.toUpper)(_.length)(_ + _)
// Map('A' -> 12, 'B' -> 15)
// Partition and map simultaneously
val numbers = List(1, 2, 3, 4, 5)
numbers.partitionMap(n => if (n % 2 == 0) Left(n * 2) else Right(n.toString))
// (List(4, 8), List("1", "3", "5"))Operations that apply side effects while preserving the original collection structure.
/**
* Apply a side effect to each element and return the original collection
* @param f Side effect function
* @param bf CanBuildFrom for result collection
* @return Original collection unchanged
*/
def tapEach[U](f: A => U)(implicit bf: CanBuildFrom[Repr, A, Repr]): ReprUsage Examples:
import scala.collection.compat._
val numbers = List(1, 2, 3, 4, 5)
// Apply side effect (logging) while preserving the collection
val result = numbers
.tapEach(n => println(s"Processing: $n"))
.map(_ * 2)
.tapEach(n => println(s"Result: $n"))
// Useful for debugging pipelines
val processed = data
.filter(predicate)
.tapEach(item => logger.debug(s"After filter: $item"))
.map(transform)
.tapEach(item => logger.debug(s"After transform: $item"))Special extension methods for Map collections including atomic updates and entry iteration.
/**
* Apply function to each key-value pair (more efficient than foreach on tuples)
* @param f Function to apply to each key-value pair
*/
def foreachEntry[U](f: (K, V) => U): Unit
/**
* Update map with remapping function (immutable maps)
* @param key Key to update
* @param remappingFunction Function that receives current value and returns new value
* @return New map with updated value
*/
def updatedWith[V1 >: V](key: K)(remappingFunction: (Option[V]) => Option[V1]): Map[K, V1]
/**
* Update map with remapping function (mutable maps)
* @param key Key to update
* @param remappingFunction Function that receives current value and returns new value
* @return Previous value if any
*/
def updateWith(key: K)(remappingFunction: (Option[V]) => Option[V]): Option[V]Usage Examples:
import scala.collection.compat._
val scores = Map("Alice" -> 85, "Bob" -> 92, "Charlie" -> 78)
// Efficient entry iteration
scores.foreachEntry { (name, score) =>
println(s"$name scored $score")
}
// Atomic map updates
val updated = scores.updatedWith("Alice") {
case Some(score) => Some(score + 10) // Bonus points
case None => Some(50) // Default score
}
// For mutable maps
val mutableScores = scala.collection.mutable.Map("Alice" -> 85)
val previousScore = mutableScores.updateWith("Alice")(_.map(_ + 5))Enhanced iterator operations including safe element access and concatenation.
/**
* Safe next element access
* @return Some(next element) or None if iterator is empty
*/
def nextOption(): Option[A]
/**
* Check if iterator elements are the same as collection elements
* @param that Collection to compare against
* @return true if all elements are equal in order
*/
def sameElements[B >: A](that: TraversableOnce[B]): Boolean
/**
* Concatenate iterator with another collection
* @param that Collection to concatenate
* @return Combined traversable
*/
def concat[B >: A](that: TraversableOnce[B]): TraversableOnce[B]Usage Examples:
import scala.collection.compat._
val iter = List(1, 2, 3).iterator
// Safe element access
while (iter.nextOption.isDefined) {
// Process elements safely
}
// Element comparison
val iter1 = List(1, 2, 3).iterator
val list2 = List(1, 2, 3)
iter1.sameElements(list2) // true
// Iterator concatenation
val combined = List(1, 2).iterator.concat(List(3, 4))