0
# Collection Extensions
1
2
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.
3
4
## Capabilities
5
6
### Safe Min/Max Operations
7
8
Safe minimum and maximum operations that return Option instead of throwing exceptions on empty collections.
9
10
```scala { .api }
11
/**
12
* Returns the minimum element as an Option, or None if empty
13
* @param ord Ordering for elements
14
* @return Some(minimum) or None if collection is empty
15
*/
16
def minOption[B >: A](implicit ord: Ordering[B]): Option[A]
17
18
/**
19
* Returns the maximum element as an Option, or None if empty
20
* @param ord Ordering for elements
21
* @return Some(maximum) or None if collection is empty
22
*/
23
def maxOption[B >: A](implicit ord: Ordering[B]): Option[A]
24
25
/**
26
* Returns the minimum element by function as an Option
27
* @param f Function to extract comparison key
28
* @param cmp Ordering for comparison keys
29
* @return Some(minimum) or None if collection is empty
30
*/
31
def minByOption[B](f: A => B)(implicit cmp: Ordering[B]): Option[A]
32
33
/**
34
* Returns the maximum element by function as an Option
35
* @param f Function to extract comparison key
36
* @param cmp Ordering for comparison keys
37
* @return Some(maximum) or None if collection is empty
38
*/
39
def maxByOption[B](f: A => B)(implicit cmp: Ordering[B]): Option[A]
40
```
41
42
**Usage Examples:**
43
44
```scala
45
import scala.collection.compat._
46
47
val numbers = List(3, 1, 4, 1, 5)
48
val empty = List.empty[Int]
49
50
numbers.minOption // Some(1)
51
numbers.maxOption // Some(5)
52
empty.minOption // None
53
empty.maxOption // None
54
55
// Min/max by function
56
case class Person(name: String, age: Int)
57
val people = List(Person("Alice", 25), Person("Bob", 30))
58
people.minByOption(_.age) // Some(Person("Alice", 25))
59
people.maxByOption(_.age) // Some(Person("Bob", 30))
60
```
61
62
### Size Comparison Operations
63
64
Efficient size comparison methods that can short-circuit evaluation for large collections.
65
66
```scala { .api }
67
/**
68
* Compare collection size with an integer
69
* @param otherSize Size to compare against
70
* @return Negative if smaller, 0 if equal, positive if larger
71
*/
72
def sizeCompare(otherSize: Int): Int
73
74
/**
75
* Compare collection size with another collection
76
* @param that Collection to compare size against
77
* @return Negative if smaller, 0 if equal, positive if larger
78
*/
79
def sizeCompare(that: Traversable[_]): Int
80
81
/**
82
* Get size comparison operations object
83
* @return SizeCompareOps for fluent size testing
84
*/
85
def sizeIs: SizeCompareOps
86
87
class SizeCompareOps {
88
def <(size: Int): Boolean
89
def <=(size: Int): Boolean
90
def ==(size: Int): Boolean
91
def !=(size: Int): Boolean
92
def >=(size: Int): Boolean
93
def >(size: Int): Boolean
94
}
95
```
96
97
**Usage Examples:**
98
99
```scala
100
import scala.collection.compat._
101
102
val data = List(1, 2, 3, 4, 5)
103
104
// Direct size comparison
105
data.sizeCompare(3) // Positive (> 0)
106
data.sizeCompare(5) // 0 (equal)
107
data.sizeCompare(10) // Negative (< 0)
108
109
// Fluent size testing
110
if (data.sizeIs > 3) println("Large collection")
111
if (data.sizeIs <= 10) println("Manageable size")
112
113
// Efficient for lazy collections
114
val stream = Stream.from(1)
115
if (stream.sizeIs > 100) println("This won't evaluate the entire stream")
116
```
117
118
### Enhanced Functional Operations
119
120
Advanced functional operations including grouping, partitioning, and deduplication.
121
122
```scala { .api }
123
/**
124
* Remove duplicate elements based on a key function
125
* @param f Function to extract comparison key
126
* @param cbf CanBuildFrom for result collection
127
* @return Collection with duplicates removed
128
*/
129
def distinctBy[B, That](f: A => B)(implicit cbf: CanBuildFrom[Repr, A, That]): That
130
131
/**
132
* Group elements by key and transform values in one operation
133
* @param key Function to extract grouping key
134
* @param f Function to transform values
135
* @param bf CanBuildFrom for value collections
136
* @return Map of grouped and transformed values
137
*/
138
def groupMap[K, B, That](key: A => K)(f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): Map[K, That]
139
140
/**
141
* Group elements by key, transform values, and reduce to single value per group
142
* @param key Function to extract grouping key
143
* @param f Function to transform values
144
* @param reduce Function to reduce multiple values to one
145
* @return Map with single reduced value per group
146
*/
147
def groupMapReduce[K, B](key: A => K)(f: A => B)(reduce: (B, B) => B): Map[K, B]
148
149
/**
150
* Partition elements and transform them simultaneously
151
* @param f Function returning Either for partitioning and transformation
152
* @param bf1 CanBuildFrom for left partition
153
* @param bf2 CanBuildFrom for right partition
154
* @return Tuple of (left partition, right partition)
155
*/
156
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)
157
```
158
159
**Usage Examples:**
160
161
```scala
162
import scala.collection.compat._
163
164
val people = List("Alice", "Bob", "Alice", "Charlie", "Bob")
165
166
// Remove duplicates by function
167
people.distinctBy(_.length) // List("Alice", "Bob")
168
169
// Group and map in one operation
170
val words = List("apple", "apricot", "banana", "blueberry")
171
words.groupMap(_.head.toUpper)(_.length)
172
// Map('A' -> List(5, 7), 'B' -> List(6, 9))
173
174
// Group, map and reduce
175
words.groupMapReduce(_.head.toUpper)(_.length)(_ + _)
176
// Map('A' -> 12, 'B' -> 15)
177
178
// Partition and map simultaneously
179
val numbers = List(1, 2, 3, 4, 5)
180
numbers.partitionMap(n => if (n % 2 == 0) Left(n * 2) else Right(n.toString))
181
// (List(4, 8), List("1", "3", "5"))
182
```
183
184
### Side Effect Operations
185
186
Operations that apply side effects while preserving the original collection structure.
187
188
```scala { .api }
189
/**
190
* Apply a side effect to each element and return the original collection
191
* @param f Side effect function
192
* @param bf CanBuildFrom for result collection
193
* @return Original collection unchanged
194
*/
195
def tapEach[U](f: A => U)(implicit bf: CanBuildFrom[Repr, A, Repr]): Repr
196
```
197
198
**Usage Examples:**
199
200
```scala
201
import scala.collection.compat._
202
203
val numbers = List(1, 2, 3, 4, 5)
204
205
// Apply side effect (logging) while preserving the collection
206
val result = numbers
207
.tapEach(n => println(s"Processing: $n"))
208
.map(_ * 2)
209
.tapEach(n => println(s"Result: $n"))
210
211
// Useful for debugging pipelines
212
val processed = data
213
.filter(predicate)
214
.tapEach(item => logger.debug(s"After filter: $item"))
215
.map(transform)
216
.tapEach(item => logger.debug(s"After transform: $item"))
217
```
218
219
### Map-Specific Extensions
220
221
Special extension methods for Map collections including atomic updates and entry iteration.
222
223
```scala { .api }
224
/**
225
* Apply function to each key-value pair (more efficient than foreach on tuples)
226
* @param f Function to apply to each key-value pair
227
*/
228
def foreachEntry[U](f: (K, V) => U): Unit
229
230
/**
231
* Update map with remapping function (immutable maps)
232
* @param key Key to update
233
* @param remappingFunction Function that receives current value and returns new value
234
* @return New map with updated value
235
*/
236
def updatedWith[V1 >: V](key: K)(remappingFunction: (Option[V]) => Option[V1]): Map[K, V1]
237
238
/**
239
* Update map with remapping function (mutable maps)
240
* @param key Key to update
241
* @param remappingFunction Function that receives current value and returns new value
242
* @return Previous value if any
243
*/
244
def updateWith(key: K)(remappingFunction: (Option[V]) => Option[V]): Option[V]
245
```
246
247
**Usage Examples:**
248
249
```scala
250
import scala.collection.compat._
251
252
val scores = Map("Alice" -> 85, "Bob" -> 92, "Charlie" -> 78)
253
254
// Efficient entry iteration
255
scores.foreachEntry { (name, score) =>
256
println(s"$name scored $score")
257
}
258
259
// Atomic map updates
260
val updated = scores.updatedWith("Alice") {
261
case Some(score) => Some(score + 10) // Bonus points
262
case None => Some(50) // Default score
263
}
264
265
// For mutable maps
266
val mutableScores = scala.collection.mutable.Map("Alice" -> 85)
267
val previousScore = mutableScores.updateWith("Alice")(_.map(_ + 5))
268
```
269
270
### Iterator Extensions
271
272
Enhanced iterator operations including safe element access and concatenation.
273
274
```scala { .api }
275
/**
276
* Safe next element access
277
* @return Some(next element) or None if iterator is empty
278
*/
279
def nextOption(): Option[A]
280
281
/**
282
* Check if iterator elements are the same as collection elements
283
* @param that Collection to compare against
284
* @return true if all elements are equal in order
285
*/
286
def sameElements[B >: A](that: TraversableOnce[B]): Boolean
287
288
/**
289
* Concatenate iterator with another collection
290
* @param that Collection to concatenate
291
* @return Combined traversable
292
*/
293
def concat[B >: A](that: TraversableOnce[B]): TraversableOnce[B]
294
```
295
296
**Usage Examples:**
297
298
```scala
299
import scala.collection.compat._
300
301
val iter = List(1, 2, 3).iterator
302
303
// Safe element access
304
while (iter.nextOption.isDefined) {
305
// Process elements safely
306
}
307
308
// Element comparison
309
val iter1 = List(1, 2, 3).iterator
310
val list2 = List(1, 2, 3)
311
iter1.sameElements(list2) // true
312
313
// Iterator concatenation
314
val combined = List(1, 2).iterator.concat(List(3, 4))
315
```