Kotlin Collection Plus Minus
Introduction
One of Kotlin's most elegant features is its operator overloading capabilities. When working with collections, Kotlin provides intuitive plus
(+) and minus
(-) operators that make adding and removing elements from collections simple and readable. These operators don't modify the original collections but rather return new ones with the specified changes applied, adhering to the functional programming principles.
In this tutorial, we'll explore how to use these operators with various collection types in Kotlin and understand when and how to apply them effectively in your code.
The Plus (+) Operator
The plus operator allows you to add elements or other collections to an existing collection, creating a new collection with the combined elements.
Adding a Single Element
val numbers = listOf(1, 2, 3)
val numbersPlus = numbers + 4
println("Original: $numbers")
println("After adding: $numbersPlus")
Output:
Original: [1, 2, 3]
After adding: [1, 2, 3, 4]
Notice that the original numbers
collection remains unchanged, while numbersPlus
is a new collection containing all original elements plus the new one.
Adding Multiple Elements
You can add multiple elements at once using the plus operator:
val numbers = listOf(1, 2, 3)
val moreNumbers = numbers + listOf(4, 5, 6)
println("Original: $numbers")
println("After adding multiple: $moreNumbers")
Output:
Original: [1, 2, 3]
After adding multiple: [1, 2, 3, 4, 5, 6]
Using with Different Collection Types
The plus operator works with various collection types:
// With Sets
val set1 = setOf("apple", "banana")
val set2 = set1 + "orange"
println("Set after adding: $set2")
// With Maps
val map1 = mapOf(1 to "one", 2 to "two")
val map2 = map1 + (3 to "three")
println("Map after adding: $map2")
Output:
Set after adding: [apple, banana, orange]
Map after adding: {1=one, 2=two, 3=three}
The Minus (-) Operator
The minus operator removes elements from a collection, returning a new collection without the specified elements.
Removing a Single Element
val numbers = listOf(1, 2, 3, 4, 5)
val numbersWithoutThree = numbers - 3
println("Original: $numbers")
println("After removing: $numbersWithoutThree")
Output:
Original: [1, 2, 3, 4, 5]
After removing: [1, 2, 4, 5]
Removing Multiple Elements
You can remove multiple elements at once:
val numbers = listOf(1, 2, 3, 4, 5)
val reduced = numbers - listOf(2, 4)
println("Original: $numbers")
println("After removing multiple: $reduced")
Output:
Original: [1, 2, 3, 4, 5]
After removing multiple: [1, 3, 5]
Using with Different Collection Types
// With Sets
val fruits = setOf("apple", "banana", "orange", "grape")
val lessFruits = fruits - setOf("banana", "grape")
println("Set after removal: $lessFruits")
// With Maps
val map = mapOf(1 to "one", 2 to "two", 3 to "three")
val smallerMap = map - 2
println("Map after removal: $smallerMap")
Output:
Set after removal: [apple, orange]
Map after removal: {1=one, 3=three}
Behind the Scenes: Plus and Minus Functions
The plus and minus operators are actually translated to function calls:
plus()
function for the+
operatorminus()
function for the-
operator
You can also use these functions directly:
val numbers = listOf(1, 2, 3)
val added = numbers.plus(4)
val removed = numbers.minus(2)
println("Original: $numbers")
println("After plus(): $added")
println("After minus(): $removed")
Output:
Original: [1, 2, 3]
After plus(): [1, 2, 3, 4]
After minus(): [1, 3]
Practical Examples
Building a Shopping Cart
class ShoppingCart {
private var items = mapOf<String, Int>()
fun addItem(item: String, quantity: Int = 1): ShoppingCart {
val newItems = items + (item to (items[item] ?: 0) + quantity)
return ShoppingCart().apply { items = newItems }
}
fun removeItem(item: String): ShoppingCart {
val newItems = items - item
return ShoppingCart().apply { items = newItems }
}
fun getItems() = items
}
// Usage
fun main() {
var cart = ShoppingCart()
cart = cart.addItem("Apple", 3)
cart = cart.addItem("Banana", 2)
println("Cart: ${cart.getItems()}")
cart = cart.removeItem("Apple")
println("After removal: ${cart.getItems()}")
}
Output:
Cart: {Apple=3, Banana=2}
After removal: {Banana=2}
Managing Tags
class Document(val title: String, val tags: Set<String>) {
fun addTags(vararg newTags: String): Document {
return Document(title, tags + newTags)
}
fun removeTags(vararg tagsToRemove: String): Document {
return Document(title, tags - tagsToRemove.toSet())
}
override fun toString(): String {
return "Document(title='$title', tags=$tags)"
}
}
fun main() {
var doc = Document("Kotlin Tutorial", setOf("programming", "kotlin"))
println("Initial: $doc")
doc = doc.addTags("beginner", "tutorial")
println("After adding tags: $doc")
doc = doc.removeTags("beginner", "programming")
println("After removing tags: $doc")
}
Output:
Initial: Document(title='Kotlin Tutorial', tags=[programming, kotlin])
After adding tags: Document(title='Kotlin Tutorial', tags=[programming, kotlin, beginner, tutorial])
After removing tags: Document(title='Kotlin Tutorial', tags=[kotlin, tutorial])
Important Considerations
-
Immutability: The plus and minus operators always return new collections rather than modifying the original ones.
-
Performance: For large collections, be mindful that creating new collections with these operators involves copying elements, which can have performance implications.
-
Duplicates: When using these operators with lists, duplicates are preserved. With sets, duplicates are automatically eliminated.
// Duplicates with lists
val list = listOf(1, 2, 2, 3)
val newList = list + 2
println(newList) // Prints: [1, 2, 2, 3, 2]
// Duplicates with sets
val set = setOf(1, 2, 3)
val newSet = set + 2
println(newSet) // Prints: [1, 2, 3] - No change because 2 already exists
- Order: The plus operation appends elements to the end of lists, preserving the original order.
Summary
Kotlin's plus and minus operators provide an elegant, functional way to manipulate collections:
- The
+
(plus) operator adds elements or merges collections - The
-
(minus) operator removes elements from collections - Both operators create new collections, preserving the originals
- They work with lists, sets, and maps, with behavior appropriate to each collection type
These operators make your code more readable and expressive when working with collections, aligning with Kotlin's philosophy of concise, expressive code.
Exercises
-
Create a function that takes a list of integers and returns a new list with all even numbers removed using the minus operator.
-
Implement a function that merges two maps using the plus operator, but if there are duplicate keys, the values should be added together (assuming numeric values).
-
Build a simple tag filtering system where users can add and remove tags from a collection using the plus and minus operators.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)