Skip to main content

Kotlin Collection Conversion

When working with Kotlin collections, you'll often need to convert between different collection types. This guide explores how to convert between lists, sets, maps, arrays, and other collection types in Kotlin, with practical examples.

Introduction to Collection Conversion

Collection conversion is the process of transforming one collection type into another. In Kotlin, the standard library provides a rich set of extension functions that make collection conversion seamless and expressive.

Common conversion scenarios include:

  • Converting between mutable and immutable collections
  • Transforming lists to sets (to remove duplicates)
  • Converting collections to arrays and vice versa
  • Transforming maps to lists of pairs
  • Converting between Java and Kotlin collections

Basic Collection Type Conversions

Converting Between List, Set, and Collection

Kotlin makes it easy to convert between the main collection types:

kotlin
fun main() {
// List to Set conversion
val numbersList = listOf(1, 2, 3, 3, 4, 5)
val numbersSet = numbersList.toSet()
println("Original list: $numbersList")
println("Converted to set: $numbersSet") // Duplicates removed

// Set to List conversion
val fruitSet = setOf("apple", "banana", "orange")
val fruitList = fruitSet.toList()
println("Original set: $fruitSet")
println("Converted to list: $fruitList")

// Converting to a generic Collection
val collection: Collection<String> = fruitList
println("As generic collection: $collection")
}

Output:

Original list: [1, 2, 3, 3, 4, 5]
Converted to set: [1, 2, 3, 4, 5]
Original set: [apple, banana, orange]
Converted to list: [apple, banana, orange]
As generic collection: [apple, banana, orange]

Converting Between Mutable and Immutable Collections

Kotlin differentiates between mutable and immutable collections. Converting between them is straightforward:

kotlin
fun main() {
// Immutable to mutable
val immutableList = listOf("red", "green", "blue")
val mutableList = immutableList.toMutableList()
mutableList.add("yellow")
println("Original immutable list: $immutableList")
println("Modified mutable list: $mutableList")

// Mutable to immutable
val readOnlyList = mutableList.toList() // Creates an immutable copy
println("Immutable copy: $readOnlyList")
}

Output:

Original immutable list: [red, green, blue]
Modified mutable list: [red, green, blue, yellow]
Immutable copy: [red, green, blue, yellow]

Arrays and Collections

Converting Arrays to Collections

Converting arrays to collections uses the same extension functions:

kotlin
fun main() {
// Array to List
val stringArray = arrayOf("Monday", "Tuesday", "Wednesday")
val stringList = stringArray.toList()
println("Array: ${stringArray.joinToString()}")
println("As List: $stringList")

// Array to Set
val intArray = intArrayOf(5, 5, 10, 15, 10)
val intSet = intArray.toSet()
println("Int Array: ${intArray.joinToString()}")
println("As Set: $intSet") // Duplicates removed

// Primitive array to collection
val doubleArray = doubleArrayOf(1.1, 2.2, 3.3)
val doubleList = doubleArray.toList()
println("Double Array: ${doubleArray.joinToString()}")
println("As List: $doubleList")
}

Output:

Array: Monday, Tuesday, Wednesday
As List: [Monday, Tuesday, Wednesday]
Int Array: 5, 5, 10, 15, 10
As Set: [5, 10, 15]
Double Array: 1.1, 2.2, 3.3
As List: [1.1, 2.2, 3.3]

Converting Collections to Arrays

You can also convert collections back to arrays:

kotlin
fun main() {
val numberList = listOf(1, 2, 3, 4, 5)

// To regular Array (type: Array<Int>)
val array = numberList.toTypedArray()
println("List as Array: ${array.joinToString()}")

// To primitive IntArray
val intArray = numberList.toIntArray()
println("List as IntArray: ${intArray.joinToString()}")

// String list to array
val stringList = listOf("hello", "world")
val stringArray = stringList.toTypedArray()
println("String list as Array: ${stringArray.joinToString()}")
}

Output:

List as Array: 1, 2, 3, 4, 5
List as IntArray: 1, 2, 3, 4, 5
String list as Array: hello, world

Map Conversions

Converting Maps to Lists and Vice Versa

Maps can be converted to lists of pairs and back again:

kotlin
fun main() {
// Map to list of pairs
val userMap = mapOf("John" to 25, "Sarah" to 30, "Mike" to 22)
val pairsList = userMap.toList()
println("Map: $userMap")
println("As list of pairs: $pairsList")

// List of pairs to map
val newMap = pairsList.toMap()
println("Back to map: $newMap")

// Converting map entries
val keysList = userMap.keys.toList()
val valuesList = userMap.values.toList()
println("Keys as list: $keysList")
println("Values as list: $valuesList")
}

Output:

Map: {John=25, Sarah=30, Mike=22}
As list of pairs: [(John, 25), (Sarah, 30), (Mike, 22)]
Back to map: {John=25, Sarah=30, Mike=22}
Keys as list: [John, Sarah, Mike]
Values as list: [25, 30, 22]

Converting Between Different Map Types

kotlin
fun main() {
// Regular map to sorted map
val regularMap = mapOf("banana" to 3, "apple" to 5, "orange" to 2)
val sortedByKey = regularMap.toSortedMap()
println("Original map: $regularMap")
println("Sorted by key: $sortedByKey")

// Converting to mutable map
val mutableUserMap = mapOf("Alice" to 29, "Bob" to 31).toMutableMap()
mutableUserMap["Charlie"] = 27
println("Modified mutable map: $mutableUserMap")
}

Output:

Original map: {banana=3, apple=5, orange=2}
Sorted by key: {apple=5, banana=3, orange=2}
Modified mutable map: {Alice=29, Bob=31, Charlie=27}

Advanced Collection Conversions

Filtering While Converting

You can combine conversion with filtering operations:

kotlin
fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

// Convert to set while filtering
val evenNumbersSet = numbers.filter { it % 2 == 0 }.toSet()
println("Even numbers as set: $evenNumbersSet")

// Create map from filtered list
val squaredEvenMap = numbers
.filter { it % 2 == 0 }
.associate { it to (it * it) }
println("Map of even numbers to their squares: $squaredEvenMap")
}

Output:

Even numbers as set: [2, 4, 6, 8, 10]
Map of even numbers to their squares: {2=4, 4=16, 6=36, 8=64, 10=100}

Converting Using Transformations

You can also transform elements during conversion:

kotlin
fun main() {
val words = listOf("apple", "banana", "cherry", "date")

// Transform while converting to set
val lengthSet = words.mapTo(mutableSetOf()) { it.length }
println("Word lengths as set: $lengthSet")

// Creating a map from a list with custom transformation
val wordMap = words.associateWith { it.uppercase() }
println("Words mapped to uppercase: $wordMap")

// Grouping during conversion
val groupedByLength = words.groupBy { it.length }
println("Words grouped by length: $groupedByLength")
}

Output:

Word lengths as set: [5, 6, 4]
Words mapped to uppercase: {apple=APPLE, banana=BANANA, cherry=CHERRY, date=DATE}
Words grouped by length: {5=[apple, cherry], 6=[banana], 4=[date]}

Practical Examples

Example 1: Processing User Data

Let's say we have user data coming from different sources and need to consolidate and process it:

kotlin
data class User(val id: Int, val name: String, val email: String)

fun main() {
// User data from different sources
val usersFromDatabase = arrayOf(
User(1, "John", "[email protected]"),
User(2, "Mary", "[email protected]")
)

val usersFromAPI = listOf(
User(3, "Peter", "[email protected]"),
User(4, "Sarah", "[email protected]")
)

val usersFromCsv = mutableListOf(
User(5, "David", "[email protected]")
)

// Consolidate all users
val allUsers = (usersFromDatabase.toList() + usersFromAPI + usersFromCsv).toSet()
println("All users: ${allUsers.size} total")

// Convert to map for quick lookups by ID
val userMap = allUsers.associateBy { it.id }
println("User with ID 3: ${userMap[3]}")

// Generate email list
val emailList = allUsers.map { it.email }.toTypedArray()
println("Email list: ${emailList.joinToString()}")
}

Output:

All users: 5 total
User with ID 3: User(id=3, name=Peter, [email protected])
Email list: [email protected], [email protected], [email protected], [email protected], [email protected]

Example 2: Data Analytics on Sales Data

Let's simulate a scenario involving sales data analysis:

kotlin
data class Sale(val productId: String, val quantity: Int, val price: Double)

fun main() {
val salesData = listOf(
Sale("A123", 5, 10.50),
Sale("B456", 2, 25.00),
Sale("A123", 3, 10.50),
Sale("C789", 1, 100.00),
Sale("B456", 1, 25.00)
)

// Group sales by product ID
val salesByProduct = salesData.groupBy { it.productId }
println("Sales grouped by product: ${salesByProduct.keys}")

// Calculate total revenue per product
val revenueByProduct = salesByProduct.mapValues { (_, sales) ->
sales.sumOf { it.quantity * it.price }
}
println("Revenue by product: $revenueByProduct")

// Convert to sorted list of pairs by revenue
val sortedProductsByRevenue = revenueByProduct.toList()
.sortedByDescending { it.second }
.toMap()
println("Products sorted by revenue: $sortedProductsByRevenue")
}

Output:

Sales grouped by product: [A123, B456, C789]
Revenue by product: {A123=84.0, B456=75.0, C789=100.0}
Products sorted by revenue: {C789=100.0, A123=84.0, B456=75.0}

Summary

Kotlin offers a comprehensive set of functions for converting between different collection types. These conversions are type-safe, concise, and often combined with transformation operations for powerful data processing. The key points to remember:

  1. Basic conversions are done with toList(), toSet(), toMap(), etc.
  2. Converting between mutable and immutable collections uses toMutableList(), toMutableSet(), etc.
  3. Arrays can be converted to collections and back using toList(), toTypedArray(), etc.
  4. Maps can be converted to lists of pairs and vice versa.
  5. Conversions can be combined with transformations like filter, map, and groupBy.
  6. Collection conversions are immutable operations - they create new collections rather than modifying existing ones.

Additional Resources and Exercises

Resources

Exercises

  1. Basic Conversion Practice: Create an array of integers with duplicates, convert it to a set to remove duplicates, then back to a list, and finally to a mutable list where you add some new elements.

  2. Map Manipulation: Create a list of strings, then convert it to a map where the keys are the strings and the values are their lengths. Then convert this map to a list of pairs sorted by the length values.

  3. Data Processing Challenge: Given a list of Person objects with name, age, and city, convert it to:

    • A map with cities as keys and lists of people as values
    • A set of all unique ages
    • An array of all names in alphabetical order
  4. Advanced Challenge: Implement a function that takes a collection of any type and converts it to a specialized collection based on a predicate function provided as a parameter.

By practicing these conversions, you'll gain fluency with Kotlin's collection API and be able to manipulate data efficiently in your applications.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)