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

map-extensions.mddocs/

0

# Map Extensions

1

2

Enhanced map operations for both immutable and mutable maps, providing additional utility methods and conditional update operations.

3

4

## General Map Extensions

5

6

### MapExtensionMethods

7

8

```scala { .api }

9

implicit class MapExtensionMethods[K, V](private val self: Map[K, V]) extends AnyVal {

10

def foreachEntry[U](f: (K, V) => U): Unit

11

}

12

```

13

14

#### foreachEntry

15

16

```scala { .api }

17

def foreachEntry[U](f: (K, V) => U): Unit

18

```

19

20

Iterate over key-value pairs with a function that takes separate key and value parameters instead of a tuple.

21

22

**Usage:**

23

```scala

24

val map = Map("a" -> 1, "b" -> 2, "c" -> 3)

25

26

// Traditional foreach with tuple

27

map.foreach { case (k, v) => println(s"$k: $v") }

28

29

// foreachEntry with separate parameters

30

map.foreachEntry { (k, v) => println(s"$k: $v") }

31

```

32

33

## Immutable Map Extensions

34

35

### ImmutableMapExtensionMethods

36

37

```scala { .api }

38

implicit class ImmutableMapExtensionMethods[K, V](

39

private val self: immutable.Map[K, V]) extends AnyVal {

40

def updatedWith[V1 >: V](key: K)(remappingFunction: Option[V] => Option[V1]): Map[K, V1]

41

}

42

```

43

44

#### updatedWith

45

46

```scala { .api }

47

def updatedWith[V1 >: V](key: K)(remappingFunction: Option[V] => Option[V1]): Map[K, V1]

48

```

49

50

Conditionally update a map entry based on the current value. The remapping function receives the current value as an `Option` and returns the new value as an `Option`.

51

52

**Behavior:**

53

- If the function returns `Some(value)`, the key is updated with the new value

54

- If the function returns `None`, the key is removed from the map

55

- The function receives `Some(currentValue)` if the key exists, `None` otherwise

56

57

**Usage:**

58

```scala

59

val map = Map("a" -> 1, "b" -> 2)

60

61

// Increment existing value or set to 1 if not present

62

val incremented = map.updatedWith("a") {

63

case Some(value) => Some(value + 1)

64

case None => Some(1)

65

}

66

// Result: Map("a" -> 2, "b" -> 2)

67

68

// Remove key conditionally

69

val filtered = map.updatedWith("a") {

70

case Some(value) if value > 1 => None // Remove if > 1

71

case other => other // Keep as is

72

}

73

// Result: Map("b" -> 2)

74

75

// Add new key

76

val withNew = map.updatedWith("c") {

77

case Some(value) => Some(value + 10)

78

case None => Some(100)

79

}

80

// Result: Map("a" -> 1, "b" -> 2, "c" -> 100)

81

```

82

83

## Mutable Map Extensions

84

85

### MutableMapExtensionMethods

86

87

```scala { .api }

88

implicit class MutableMapExtensionMethods[K, V](

89

private val self: mutable.Map[K, V]) extends AnyVal {

90

def updateWith(key: K)(remappingFunction: Option[V] => Option[V]): Option[V]

91

}

92

```

93

94

#### updateWith

95

96

```scala { .api }

97

def updateWith(key: K)(remappingFunction: Option[V] => Option[V]): Option[V]

98

```

99

100

Conditionally update a mutable map entry in-place. Similar to `updatedWith` but modifies the map directly and returns the final value.

101

102

**Returns:** The final value associated with the key after the update, or `None` if the key was removed.

103

104

**Usage:**

105

```scala

106

val map = mutable.Map("a" -> 1, "b" -> 2)

107

108

// Increment existing value or set to 1 if not present

109

val result1 = map.updateWith("a") {

110

case Some(value) => Some(value + 1)

111

case None => Some(1)

112

}

113

// map is now Map("a" -> 2, "b" -> 2)

114

// result1 is Some(2)

115

116

// Remove key conditionally

117

val result2 = map.updateWith("a") {

118

case Some(value) if value > 1 => None

119

case other => other

120

}

121

// map is now Map("b" -> 2)

122

// result2 is None

123

124

// Add new key

125

val result3 = map.updateWith("c") {

126

case Some(value) => Some(value + 10)

127

case None => Some(100)

128

}

129

// map is now Map("b" -> 2, "c" -> 100)

130

// result3 is Some(100)

131

```

132

133

## Map View Extensions

134

135

### MapViewExtensionMethods

136

137

```scala { .api }

138

implicit class MapViewExtensionMethods[K, V, C <: Map[K, V]](

139

private val self: IterableView[(K, V), C]) extends AnyVal {

140

def mapValues[W, That](f: V => W): That

141

def filterKeys(p: K => Boolean): IterableView[(K, V), C]

142

}

143

```

144

145

Extensions for map views that provide lazy transformation operations.

146

147

#### mapValues

148

149

```scala { .api }

150

def mapValues[W, That](f: V => W): That

151

```

152

153

Transform the values in a map view lazily.

154

155

**Usage:**

156

```scala

157

val map = Map("a" -> 1, "b" -> 2, "c" -> 3)

158

val view = map.view

159

160

val doubled = view.mapValues(_ * 2)

161

// Lazy view - values not computed until accessed

162

doubled.force // Map("a" -> 2, "b" -> 4, "c" -> 6)

163

```

164

165

#### filterKeys

166

167

```scala { .api }

168

def filterKeys(p: K => Boolean): IterableView[(K, V), C]

169

```

170

171

Filter map entries by keys in a lazy view.

172

173

**Usage:**

174

```scala

175

val map = Map("apple" -> 1, "banana" -> 2, "apricot" -> 3)

176

val view = map.view

177

178

val aWords = view.filterKeys(_.startsWith("a"))

179

// Lazy view - filtering not applied until accessed

180

aWords.force // Map("apple" -> 1, "apricot" -> 3)

181

```

182

183

## Complete Usage Examples

184

185

### Cache Implementation with updatedWith

186

187

```scala

188

import scala.collection.compat._

189

190

case class CacheEntry[T](value: T, timestamp: Long)

191

192

class Cache[K, V] {

193

private var store = Map.empty[K, CacheEntry[V]]

194

private val ttlMs = 60000 // 1 minute TTL

195

196

def get(key: K): Option[V] = {

197

val now = System.currentTimeMillis()

198

store.get(key) match {

199

case Some(entry) if now - entry.timestamp < ttlMs =>

200

Some(entry.value)

201

case _ =>

202

store = store.updatedWith(key)(_ => None) // Remove expired entry

203

None

204

}

205

}

206

207

def put(key: K, value: V): Unit = {

208

val now = System.currentTimeMillis()

209

store = store.updatedWith(key)(_ => Some(CacheEntry(value, now)))

210

}

211

}

212

```

213

214

### Statistics Collection with updateWith

215

216

```scala

217

import scala.collection.{mutable, compat}

218

import compat._

219

220

val stats = mutable.Map.empty[String, Int]

221

222

def recordEvent(event: String): Unit = {

223

stats.updateWith(event) {

224

case Some(count) => Some(count + 1)

225

case None => Some(1)

226

}

227

}

228

229

recordEvent("login") // stats: Map("login" -> 1)

230

recordEvent("logout") // stats: Map("login" -> 1, "logout" -> 1)

231

recordEvent("login") // stats: Map("login" -> 2, "logout" -> 1)

232

```

233

234

### Configuration Updates

235

236

```scala

237

case class Config(timeout: Int, retries: Int, enabled: Boolean)

238

239

val baseConfig = Map(

240

"api" -> Config(5000, 3, true),

241

"db" -> Config(30000, 1, true)

242

)

243

244

// Disable a service conditionally

245

val updatedConfig = baseConfig.updatedWith("api") {

246

case Some(config) if config.timeout > 10000 => Some(config.copy(enabled = false))

247

case other => other

248

}

249

250

// Add new service configuration

251

val withNewService = updatedConfig.updatedWith("cache") {

252

case Some(existing) => Some(existing) // Keep existing

253

case None => Some(Config(1000, 5, true)) // Add new

254

}

255

```

256

257

### Bulk Map Operations

258

259

```scala

260

def processUserPreferences(

261

current: Map[String, String],

262

updates: List[(String, Option[String])]

263

): Map[String, String] = {

264

updates.foldLeft(current) { case (map, (key, valueOpt)) =>

265

map.updatedWith(key)(_ => valueOpt)

266

}

267

}

268

269

val prefs = Map("theme" -> "dark", "lang" -> "en")

270

val updates = List(

271

"theme" -> Some("light"), // Update existing

272

"lang" -> None, // Remove existing

273

"region" -> Some("us") // Add new

274

)

275

276

val result = processUserPreferences(prefs, updates)

277

// Result: Map("theme" -> "light", "region" -> "us")

278

```

279

280

### Map View Processing

281

282

```scala

283

val inventory = Map(

284

"laptop" -> 999.99,

285

"mouse" -> 29.99,

286

"keyboard" -> 79.99,

287

"monitor" -> 299.99

288

)

289

290

// Chain view operations for efficient processing

291

val expensiveItems = inventory.view

292

.filterKeys(!_.contains("mouse")) // Exclude mice

293

.mapValues(_ * 1.1) // Add 10% markup

294

.filter(_._2 > 100) // Only expensive items

295

.toMap

296

297

// Result: Map("laptop" -> 1099.989, "monitor" -> 329.989)

298

```

299

300

## Implementation Notes

301

302

- `updatedWith` creates a new immutable map, preserving the original

303

- `updateWith` modifies the mutable map in-place and returns the result value

304

- Map view operations are lazy and only computed when the view is forced

305

- These methods provide functional approaches to conditional map updates

306

- The remapping functions follow the same pattern as Java 8's `Map.compute` methods