or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotation-backports.mdbackported-collections.mdcollection-extensions.mdcollection-factories.mdindex.mditerator-size-ops.mdjava-interop.mdmap-extensions.mdmethod-chaining.mdoption-converters.mdresource-management.mdstring-parsing.md

collection-extensions.mddocs/

0

# Collection Extensions

1

2

Enhanced collection operations including safe min/max methods, advanced transformations, and functional programming utilities.

3

4

## Safe Min/Max Operations

5

6

### TraversableOnceExtensionMethods

7

8

```scala { .api }

9

implicit class TraversableOnceExtensionMethods[A](private val self: TraversableOnce[A])

10

extends AnyVal {

11

def minOption[B >: A](implicit ord: Ordering[B]): Option[A]

12

def maxOption[B >: A](implicit ord: Ordering[B]): Option[A]

13

def minByOption[B](f: A => B)(implicit cmp: Ordering[B]): Option[A]

14

def maxByOption[B](f: A => B)(implicit cmp: Ordering[B]): Option[A]

15

}

16

```

17

18

Safe versions of min/max operations that return `Option` instead of throwing exceptions on empty collections.

19

20

#### minOption / maxOption

21

22

```scala { .api }

23

def minOption[B >: A](implicit ord: Ordering[B]): Option[A]

24

def maxOption[B >: A](implicit ord: Ordering[B]): Option[A]

25

```

26

27

Find the minimum or maximum element in a collection.

28

29

**Returns:**

30

- `Some(element)` if the collection is non-empty

31

- `None` if the collection is empty

32

33

**Usage:**

34

```scala

35

List(3, 1, 4, 1, 5).minOption // Some(1)

36

List(3, 1, 4, 1, 5).maxOption // Some(5)

37

List.empty[Int].minOption // None

38

List.empty[Int].maxOption // None

39

```

40

41

#### minByOption / maxByOption

42

43

```scala { .api }

44

def minByOption[B](f: A => B)(implicit cmp: Ordering[B]): Option[A]

45

def maxByOption[B](f: A => B)(implicit cmp: Ordering[B]): Option[A]

46

```

47

48

Find the element that produces the minimum or maximum value when the function is applied.

49

50

**Usage:**

51

```scala

52

case class Person(name: String, age: Int)

53

val people = List(Person("Alice", 25), Person("Bob", 30), Person("Charlie", 20))

54

55

people.minByOption(_.age) // Some(Person("Charlie", 20))

56

people.maxByOption(_.age) // Some(Person("Bob", 30))

57

List.empty[Person].minByOption(_.age) // None

58

```

59

60

## Advanced Collection Transformations

61

62

### TraversableLikeExtensionMethods

63

64

```scala { .api }

65

implicit class TraversableLikeExtensionMethods[A, Repr](

66

private val self: GenTraversableLike[A, Repr]) extends AnyVal {

67

def tapEach[U](f: A => U)(implicit bf: CanBuildFrom[Repr, A, Repr]): Repr

68

def partitionMap[A1, A2, That, Repr1, Repr2](f: A => Either[A1, A2]): (Repr1, Repr2)

69

def groupMap[K, B, That](key: A => K)(f: A => B): Map[K, That]

70

def groupMapReduce[K, B](key: A => K)(f: A => B)(reduce: (B, B) => B): Map[K, B]

71

def distinctBy[B, That](f: A => B): That

72

}

73

```

74

75

#### tapEach

76

77

```scala { .api }

78

def tapEach[U](f: A => U)(implicit bf: CanBuildFrom[Repr, A, Repr]): Repr

79

```

80

81

Apply a function to each element for its side effects and return the original collection unchanged.

82

83

**Usage:**

84

```scala

85

List(1, 2, 3)

86

.tapEach(println) // prints 1, 2, 3

87

.map(_ * 2) // List(2, 4, 6)

88

```

89

90

#### partitionMap

91

92

```scala { .api }

93

def partitionMap[A1, A2, That, Repr1, Repr2](f: A => Either[A1, A2]): (Repr1, Repr2)

94

```

95

96

Partition a collection into two collections based on a function that returns `Either`.

97

98

**Usage:**

99

```scala

100

val numbers = List(1, 2, 3, 4, 5, 6)

101

val (evens, odds) = numbers.partitionMap { n =>

102

if (n % 2 == 0) Left(n) else Right(n)

103

}

104

// evens: List(2, 4, 6)

105

// odds: List(1, 3, 5)

106

```

107

108

#### groupMap

109

110

```scala { .api }

111

def groupMap[K, B, That](key: A => K)(f: A => B): Map[K, That]

112

```

113

114

Group elements by a key function and transform them with a mapping function in one operation.

115

116

**Usage:**

117

```scala

118

case class Student(name: String, grade: Char, score: Int)

119

val students = List(

120

Student("Alice", 'A', 95),

121

Student("Bob", 'B', 85),

122

Student("Charlie", 'A', 92)

123

)

124

125

val scoresByGrade = students.groupMap(_.grade)(_.score)

126

// Map('A' -> List(95, 92), 'B' -> List(85))

127

```

128

129

#### groupMapReduce

130

131

```scala { .api }

132

def groupMapReduce[K, B](key: A => K)(f: A => B)(reduce: (B, B) => B): Map[K, B]

133

```

134

135

Group elements by a key, transform them, and reduce the values in each group.

136

137

**Usage:**

138

```scala

139

val students = List(

140

Student("Alice", 'A', 95),

141

Student("Bob", 'B', 85),

142

Student("Charlie", 'A', 92)

143

)

144

145

val avgScoreByGrade = students.groupMapReduce(_.grade)(_.score)(_ + _)

146

// Map('A' -> 187, 'B' -> 85) // Note: sum, not average

147

```

148

149

#### distinctBy

150

151

```scala { .api }

152

def distinctBy[B, That](f: A => B): That

153

```

154

155

Remove duplicate elements based on the result of a key function.

156

157

**Usage:**

158

```scala

159

case class Person(name: String, age: Int)

160

val people = List(

161

Person("Alice", 25),

162

Person("Bob", 30),

163

Person("Alice", 26) // duplicate name

164

)

165

166

val uniqueByName = people.distinctBy(_.name)

167

// List(Person("Alice", 25), Person("Bob", 30))

168

```

169

170

## Size Comparison Operations

171

172

### SizeCompareOps

173

174

```scala { .api }

175

class SizeCompareOps(private val it: Traversable[_]) extends AnyVal {

176

def <(size: Int): Boolean

177

def <=(size: Int): Boolean

178

def ==(size: Int): Boolean

179

def !=(size: Int): Boolean

180

def >=(size: Int): Boolean

181

def >(size: Int): Boolean

182

}

183

```

184

185

Efficient size comparison operations that can short-circuit for better performance with large collections.

186

187

**Usage:**

188

```scala

189

val list = List(1, 2, 3, 4, 5)

190

191

// Size comparisons

192

list.sizeIs < 10 // true

193

list.sizeIs >= 5 // true

194

list.sizeIs == 5 // true

195

list.sizeIs != 3 // true

196

197

// Sequence length comparisons

198

val seq = Seq(1, 2, 3)

199

seq.lengthIs > 2 // true

200

seq.lengthIs <= 5 // true

201

```

202

203

## Collection Utility Extensions

204

205

### TraversableExtensionMethods

206

207

```scala { .api }

208

implicit class TraversableExtensionMethods[A](private val self: Traversable[A])

209

extends AnyVal {

210

def iterableFactory: GenericCompanion[Traversable]

211

def sizeCompare(otherSize: Int): Int

212

def sizeIs: SizeCompareOps

213

def sizeCompare(that: Traversable[_]): Int

214

}

215

```

216

217

#### sizeCompare

218

219

```scala { .api }

220

def sizeCompare(otherSize: Int): Int

221

def sizeCompare(that: Traversable[_]): Int

222

```

223

224

Compare the size of a collection with an integer or another collection efficiently.

225

226

**Returns:**

227

- Negative value if collection is smaller

228

- Zero if sizes are equal

229

- Positive value if collection is larger

230

231

**Usage:**

232

```scala

233

val list1 = List(1, 2, 3)

234

val list2 = List(4, 5)

235

236

list1.sizeCompare(5) // negative (3 < 5)

237

list1.sizeCompare(3) // zero (3 == 3)

238

list1.sizeCompare(list2) // positive (3 > 2)

239

```

240

241

### SeqExtensionMethods

242

243

```scala { .api }

244

implicit class SeqExtensionMethods[A](private val self: Seq[A]) extends AnyVal {

245

def lengthIs: SizeCompareOps

246

}

247

```

248

249

Size comparison operations specifically for sequences.

250

251

## Complete Usage Examples

252

253

### Processing Data with Safe Operations

254

255

```scala

256

import scala.collection.compat._

257

258

case class Sale(product: String, amount: Double, region: String)

259

val sales = List(

260

Sale("laptop", 999.99, "north"),

261

Sale("mouse", 29.99, "south"),

262

Sale("laptop", 899.99, "north"),

263

Sale("keyboard", 79.99, "south")

264

)

265

266

// Safe aggregations

267

val maxSale = sales.maxByOption(_.amount) // Some(Sale("laptop", 999.99, "north"))

268

val minSale = sales.minByOption(_.amount) // Some(Sale("mouse", 29.99, "south"))

269

270

// Group and aggregate

271

val totalByRegion = sales.groupMapReduce(_.region)(_.amount)(_ + _)

272

// Map("north" -> 1899.98, "south" -> 109.98)

273

274

// Unique products by region

275

val productsByRegion = sales.groupMap(_.region)(_.product)

276

.view.mapValues(_.distinctBy(identity)).toMap

277

278

// Process with side effects

279

val processedSales = sales

280

.tapEach(sale => println(s"Processing ${sale.product}"))

281

.filter(_.amount > 50)

282

```

283

284

### Functional Processing Pipeline

285

286

```scala

287

def processNumbers(numbers: List[Int]): Map[String, List[Int]] = {

288

numbers

289

.tapEach(n => if (n < 0) println(s"Warning: negative number $n"))

290

.partitionMap { n =>

291

if (n % 2 == 0) Left(("even", n)) else Right(("odd", n))

292

} match {

293

case (evens, odds) =>

294

Map("even" -> evens.map(_._2), "odd" -> odds.map(_._2))

295

}

296

}

297

```