or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

backported-collections.mdcollection-extensions.mdindex.mdjava-conversion.mdresource-management.mdstring-parsing.mdutility-features.md
tile.json

collection-extensions.mddocs/

Collection Extensions

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.

Capabilities

Safe Min/Max Operations

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))

Size Comparison Operations

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")

Enhanced Functional Operations

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"))

Side Effect Operations

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]): Repr

Usage 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"))

Map-Specific Extensions

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))

Iterator Extensions

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))