Kotlin Set

A Kotlin set is a generic collection interface that stores unique elements without allowing duplicates. The Kotlin set collection provides two main categories: immutable sets created with setOf() and mutable sets created with mutableSetOf(). Every Kotlin set implementation automatically handles duplicate removal, making it perfect for scenarios where data uniqueness is essential.

The Kotlin set interface extends the Collection interface and provides specialized operations for set-specific functionality like union, intersection, and difference operations.

Types of Kotlin Set Implementations

1. Immutable Set with setOf()

The setOf() function creates a read-only Kotlin set that supports only read operations. This Kotlin set implementation returns a LinkedHashSet typed as Set interface, preserving insertion order while preventing modifications.

// Creating immutable Kotlin set  
val colors = setOf("Red", "Green", "Blue")  
val numbers = setOf(1, 2, 3, 4, 5)  
val mixedSet = setOf("Hello", 42, true)  

Key Properties of setOf():

  • Immutable: Cannot add or remove elements after creation
  • Insertion Order: Maintains the order elements were added
  • Null Safety: Can contain one null element
  • Type Safety: Elements must be of compatible types

2. Mutable Set with mutableSetOf()

The mutableSetOf() function creates a Kotlin set that supports both read and write operations. This Kotlin set implementation returns a LinkedHashSet that allows modifications while maintaining insertion order.

// Creating mutable Kotlin set  
val mutableColors = mutableSetOf("Red", "Green", "Blue")  
mutableColors.add("Yellow")  
mutableColors.remove("Red")  

Key Properties of mutableSetOf():

  • Mutable: Supports add, remove, and clear operations
  • Dynamic Size: Can grow or shrink during runtime
  • Insertion Order: Preserves element insertion sequence
  • Thread Safety: Not thread-safe, requires external synchronization

3. HashSet with hashSetOf()

The hashSetOf() function creates a Kotlin set using HashSet implementation, providing fastest performance for basic operations but without guaranteed iteration order.

// Creating HashSet-based Kotlin set  
val hashNumbers = hashSetOf(10, 20, 30, 40)  
hashNumbers.add(50)  
println(hashNumbers) // Order may vary: [20, 40, 10, 50, 30]  

Key Properties of hashSetOf():

  • Performance: O(1) average time for add, remove, contains
  • No Order Guarantee: Iteration order is unpredictable
  • Hash-Based: Uses hash table for element storage
  • Memory Efficient: Lower memory overhead compared to LinkedHashSet

4. LinkedHashSet with linkedSetOf()

The linkedSetOf() function creates a Kotlin set that combines HashSet performance with insertion order maintenance.

// Creating LinkedHashSet-based Kotlin set  
val linkedColors = linkedSetOf("Purple", "Orange", "Pink")  
linkedColors.add("Cyan")  
println(linkedColors) // [Purple, Orange, Pink, Cyan]  

Key Properties of linkedSetOf():

  • Ordered Iteration: Maintains insertion order
  • Good Performance: Nearly O(1) performance like HashSet
  • Memory Overhead: Additional memory for maintaining order
  • Predictable: Consistent iteration behavior

5. Sorted Set with sortedSetOf()

The sortedSetOf() function creates a Kotlin set that automatically sorts elements using natural ordering or custom comparator.

// Creating sorted Kotlin set  
val sortedNumbers = sortedSetOf(5, 1, 9, 3, 7)  
println(sortedNumbers) // [1, 3, 5, 7, 9]  
  
val sortedStrings = sortedSetOf("Zebra", "Apple", "Banana")  
println(sortedStrings) // [Apple, Banana, Zebra]  

Key Properties of sortedSetOf():

  • Automatic Sorting: Elements stored in sorted order
  • TreeSet Implementation: Uses Red-Black tree internally
  • O(log n) Performance: Logarithmic time for basic operations
  • Range Operations: Supports subSet, headSet, tailSet operations

Kotlin Set Operations and Methods

Basic Set Operations

Every Kotlin set provides essential methods for element management and querying:

val programmingLanguages = mutableSetOf("Kotlin", "Java", "Python")  
  
// Check if element exists  
val hasKotlin = programmingLanguages.contains("Kotlin") // true  
val hasSwift = "Swift" in programmingLanguages // false  
  
// Get set size  
val size = programmingLanguages.size // 3  
  
// Check if empty  
val isEmpty = programmingLanguages.isEmpty() // false  
  
// Add elements  
programmingLanguages.add("JavaScript")  
programmingLanguages.addAll(listOf("Go", "Rust"))  
  
// Remove elements  
programmingLanguages.remove("Python")  
programmingLanguages.removeAll(listOf("Go", "Rust"))  

Set Mathematical Operations

Kotlin set collections support mathematical set operations for combining and comparing sets:

Union Operation

val frontend = setOf("JavaScript", "TypeScript", "Vue")  
val backend = setOf("Kotlin", "Java", "Python")  
  
// Union combines all unique elements  
val fullStack = frontend union backend  
println(fullStack) // [JavaScript, TypeScript, Vue, Kotlin, Java, Python]  

Intersection Operation

val kotlinSkills = setOf("Android", "Backend", "Multiplatform")  
val javaSkills = setOf("Backend", "Enterprise", "Android")  
  
// Intersection finds common elements  
val commonSkills = kotlinSkills intersect javaSkills  
println(commonSkills) // [Android, Backend]  

Difference Operation

val allFrameworks = setOf("Spring", "Ktor", "Micronaut", "Quarkus")  
val javaFrameworks = setOf("Spring", "Micronaut", "Quarkus")  
  
// Difference finds elements in first set but not in second  
val kotlinFrameworks = allFrameworks subtract javaFrameworks  
println(kotlinFrameworks) // [Ktor]  

Symmetric Difference

val androidLibs = setOf("Jetpack", "Compose", "Room")  
val iosLibs = setOf("SwiftUI", "CoreData", "Combine")  
  
// Symmetric difference: elements in either set but not both  
val platformSpecific = (androidLibs - iosLibs) union (iosLibs - androidLibs)  
println(platformSpecific) // [Jetpack, Compose, Room, SwiftUI, CoreData, Combine]  

Set Transformation and Filtering

Kotlin set collections support functional programming operations for data transformation:

val numbers = setOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)  
  
// Filter elements  
val evenNumbers = numbers.filter { it % 2 == 0 }.toSet()  
println(evenNumbers) // [2, 4, 6, 8, 10]  
  
// Transform elements  
val squaredNumbers = numbers.map { it * it }.toSet()  
println(squaredNumbers) // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]  
  
// Find elements  
val firstEven = numbers.first { it % 2 == 0 } // 2  
val lastOdd = numbers.last { it % 2 == 1 } // 9  
  
// Aggregate operations  
val sum = numbers.sum() // 55  
val max = numbers.maxOrNull() // 10  
val min = numbers.minOrNull() // 1  

Converting Between Set Types

Kotlin set implementations can be converted between mutable and immutable versions:

// Convert mutable to immutable  
val mutableDevices = mutableSetOf("Android", "iOS", "Web")  
val immutableDevices: Set<String> = mutableDevices.toSet()  
  
// Convert immutable to mutable  
val readOnlyColors = setOf("Red", "Green", "Blue")  
val mutableColors: MutableSet<String> = readOnlyColors.toMutableSet()  
  
// Convert to specific implementations  
val hashSet: HashSet<String> = readOnlyColors.toCollection(HashSet())  
val linkedHashSet: LinkedHashSet<String> = readOnlyColors.toCollection(LinkedHashSet())  

Performance Characteristics

Understanding Kotlin set performance helps choose the right implementation:

Kotlin Set TypeAdd/RemoveContainsIterationMemoryOrder
HashSetO(1)O(1)O(n)LowNone
LinkedHashSetO(1)O(1)O(n)MediumInsertion
TreeSetO(log n)O(log n)O(n)MediumSorted

Real-World Examples

Example 1: User Permission Management

data class User(val id: String, val name: String)  
data class Permission(val name: String, val level: Int)  
  
class PermissionManager {  
    private val userPermissions = mutableMapOf<User, MutableSet<Permission>>()  
      
    fun grantPermission(user: User, permission: Permission) {  
        userPermissions.getOrPut(user) { mutableSetOf() }.add(permission)  
    }  
      
    fun revokePermission(user: User, permission: Permission) {  
        userPermissions[user]?.remove(permission)  
    }  
      
    fun hasPermission(user: User, permission: Permission): Boolean {  
        return userPermissions[user]?.contains(permission) ?: false  
    }  
      
    fun getCommonPermissions(user1: User, user2: User): Set<Permission> {  
        val permissions1 = userPermissions[user1] ?: emptySet()  
        val permissions2 = userPermissions[user2] ?: emptySet()  
        return permissions1 intersect permissions2  
    }  
}  

Example 2: Tag System for Content Management

data class Article(val id: String, val title: String, val tags: MutableSet<String>)  
  
class ArticleManager {  
    private val articles = mutableListOf<Article>()  
      
    fun addArticle(article: Article) {  
        articles.add(article)  
    }  
      
    fun findArticlesByTag(tag: String): List<Article> {  
        return articles.filter { tag in it.tags }  
    }  
      
    fun findArticlesByAnyTag(tags: Set<String>): List<Article> {  
        return articles.filter { article ->  
            (article.tags intersect tags).isNotEmpty()  
        }  
    }  
      
    fun findArticlesByAllTags(tags: Set<String>): List<Article> {  
        return articles.filter { article ->  
            tags.all { tag -> tag in article.tags }  
        }  
    }  
      
    fun getAllTags(): Set<String> {  
        return articles.flatMap { it.tags }.toSet()  
    }  
      
    fun getPopularTags(minCount: Int): Set<String> {  
        val tagCounts = mutableMapOf<String, Int>()  
        articles.forEach { article ->  
            article.tags.forEach { tag ->  
                tagCounts[tag] = tagCounts.getOrDefault(tag, 0) + 1  
            }  
        }  
        return tagCounts.filterValues { it >= minCount }.keys.toSet()  
    }  
}  

Example 3: Dependency Management System

data class Dependency(val name: String, val version: String)  
  
class DependencyResolver {  
    private val projectDependencies = mutableSetOf<Dependency>()  
    private val optionalDependencies = mutableSetOf<Dependency>()  
      
    fun addDependency(dependency: Dependency, optional: Boolean = false) {  
        if (optional) {  
            optionalDependencies.add(dependency)  
        } else {  
            projectDependencies.add(dependency)  
        }  
    }  
      
    fun getAllDependencies(): Set<Dependency> {  
        return projectDependencies union optionalDependencies  
    }  
      
    fun getRequiredDependencies(): Set<Dependency> {  
        return projectDependencies.toSet()  
    }  
      
    fun getOptionalDependencies(): Set<Dependency> {  
        return optionalDependencies.toSet()  
    }  
      
    fun resolveDependencies(): Set<Dependency> {  
        val resolved = mutableSetOf<Dependency>()  
          
        // Add all required dependencies  
        resolved.addAll(projectDependencies)  
          
        // Add optional dependencies that don't conflict  
        optionalDependencies.forEach { optional ->  
            val conflicts = resolved.any { existing ->  
                existing.name == optional.name && existing.version != optional.version  
            }  
            if (!conflicts) {  
                resolved.add(optional)  
            }  
        }  
          
        return resolved  
    }  
}  

Complete Working Example with Output

Here’s a comprehensive example demonstrating all Kotlin set concepts with imports and expected output:

import kotlin.random.Random  
  
fun main() {  
    println("=== Kotlin Set Comprehensive Example ===\n")  
      
    // 1. Creating different types of sets  
    println("1. Creating Different Set Types:")  
    val immutableColors = setOf("Red", "Green", "Blue", "Red") // Duplicate ignored  
    val mutableNumbers = mutableSetOf(1, 2, 3)  
    val hashSet = hashSetOf("Apple", "Banana", "Cherry")  
    val linkedSet = linkedSetOf("First", "Second", "Third")  
    val sortedSet = sortedSetOf(5, 1, 9, 3, 7)  
      
    println("Immutable Set: $immutableColors")  
    println("Mutable Set: $mutableNumbers")  
    println("Hash Set: $hashSet")  
    println("Linked Set: $linkedSet")  
    println("Sorted Set: $sortedSet\n")  
      
    // 2. Set operations  
    println("2. Set Operations:")  
    mutableNumbers.add(4)  
    mutableNumbers.addAll(listOf(5, 6, 7))  
    println("After adding elements: $mutableNumbers")  
      
    mutableNumbers.remove(1)  
    mutableNumbers.removeAll(listOf(6, 7))  
    println("After removing elements: $mutableNumbers")  
      
    println("Contains 3: ${mutableNumbers.contains(3)}")  
    println("Contains 10: ${10 in mutableNumbers}")  
    println("Set size: ${mutableNumbers.size}")  
    println("Is empty: ${mutableNumbers.isEmpty()}\n")  
      
    // 3. Mathematical set operations  
    println("3. Mathematical Set Operations:")  
    val frontend = setOf("HTML", "CSS", "JavaScript", "React")  
    val backend = setOf("Kotlin", "Java", "Python", "JavaScript")  
      
    val union = frontend union backend  
    val intersection = frontend intersect backend  
    val difference = frontend subtract backend  
    val symmetricDiff = (frontend - backend) union (backend - frontend)  
      
    println("Frontend: $frontend")  
    println("Backend: $backend")  
    println("Union: $union")  
    println("Intersection: $intersection")  
    println("Frontend - Backend: $difference")  
    println("Symmetric Difference: $symmetricDiff\n")  
      
    // 4. Functional operations  
    println("4. Functional Operations:")  
    val numbers = setOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)  
      
    val evenNumbers = numbers.filter { it % 2 == 0 }.toSet()  
    val squaredNumbers = numbers.map { it * it }.toSet()  
    val numbersAboveFive = numbers.filter { it > 5 }.toSet()  
      
    println("Original: $numbers")  
    println("Even numbers: $evenNumbers")  
    println("Squared numbers: $squaredNumbers")  
    println("Numbers > 5: $numbersAboveFive")  
      
    val sum = numbers.sum()  
    val max = numbers.maxOrNull()  
    val min = numbers.minOrNull()  
    val average = numbers.average()  
      
    println("Sum: $sum, Max: $max, Min: $min, Average: $average\n")  
      
    // 5. Real-world example: Student Course Management  
    println("5. Student Course Management System:")  
      
    data class Student(val id: String, val name: String)  
    data class Course(val code: String, val name: String)  
      
    class CourseManager {  
        private val studentCourses = mutableMapOf<Student, MutableSet<Course>>()  
          
        fun enrollStudent(student: Student, course: Course) {  
            studentCourses.getOrPut(student) { mutableSetOf() }.add(course)  
        }  
          
        fun getStudentCourses(student: Student): Set<Course> {  
            return studentCourses[student]?.toSet() ?: emptySet()  
        }  
          
        fun getCommonCourses(student1: Student, student2: Student): Set<Course> {  
            val courses1 = studentCourses[student1] ?: emptySet()  
            val courses2 = studentCourses[student2] ?: emptySet()  
            return courses1 intersect courses2  
        }  
          
        fun getAllCourses(): Set<Course> {  
            return studentCourses.values.flatten().toSet()  
        }  
          
        fun getStudentsInCourse(course: Course): Set<Student> {  
            return studentCourses.filterValues { courses -> course in courses }.keys.toSet()  
        }  
    }  
      
    val courseManager = CourseManager()  
      
    val alice = Student("1", "Alice")  
    val bob = Student("2", "Bob")  
    val charlie = Student("3", "Charlie")  
      
    val kotlin = Course("CS101", "Kotlin Programming")  
    val android = Course("CS102", "Android Development")  
    val algorithms = Course("CS201", "Data Structures & Algorithms")  
    val databases = Course("CS301", "Database Systems")  
      
    // Enroll students  
    courseManager.enrollStudent(alice, kotlin)  
    courseManager.enrollStudent(alice, android)  
    courseManager.enrollStudent(alice, algorithms)  
      
    courseManager.enrollStudent(bob, kotlin)  
    courseManager.enrollStudent(bob, algorithms)  
    courseManager.enrollStudent(bob, databases)  
      
    courseManager.enrollStudent(charlie, android)  
    courseManager.enrollStudent(charlie, databases)  
      
    println("Alice's courses: ${courseManager.getStudentCourses(alice).map { it.name }}")  
    println("Bob's courses: ${courseManager.getStudentCourses(bob).map { it.name }}")  
    println("Charlie's courses: ${courseManager.getStudentCourses(charlie).map { it.name }}")  
      
    println("Common courses (Alice & Bob): ${courseManager.getCommonCourses(alice, bob).map { it.name }}")  
    println("All courses: ${courseManager.getAllCourses().map { it.name }}")  
    println("Students in Kotlin course: ${courseManager.getStudentsInCourse(kotlin).map { it.name }}")  
      
    // 6. Performance comparison demonstration  
    println("\n6. Performance Comparison:")  
    val testSize = 10000  
      
    // HashSet performance  
    val hashSetTest = hashSetOf<Int>()  
    val hashSetTime = measureTimeMillis {  
        repeat(testSize) { hashSetTest.add(Random.nextInt()) }  
    }  
      
    // LinkedHashSet performance  
    val linkedSetTest = linkedSetOf<Int>()  
    val linkedSetTime = measureTimeMillis {  
        repeat(testSize) { linkedSetTest.add(Random.nextInt()) }  
    }  
      
    // TreeSet performance  
    val treeSetTest = sortedSetOf<Int>()  
    val treeSetTime = measureTimeMillis {  
        repeat(testSize) { treeSetTest.add(Random.nextInt()) }  
    }  
      
    println("Performance for $testSize operations:")  
    println("HashSet: ${hashSetTime}ms")  
    println("LinkedHashSet: ${linkedSetTime}ms")  
    println("TreeSet: ${treeSetTime}ms")  
      
    println("\nSet sizes after operations:")  
    println("HashSet: ${hashSetTest.size}")  
    println("LinkedHashSet: ${linkedSetTest.size}")  
    println("TreeSet: ${treeSetTest.size}")  
}  
  
// Extension function for measuring time  
fun measureTimeMillis(action: () -> Unit): Long {  
    val start = System.currentTimeMillis()  
    action()  
    return System.currentTimeMillis() - start  
}  

Expected Output:

=== Kotlin Set Comprehensive Example ===  
  
1. Creating Different Set Types:  
Immutable Set: [Red, Green, Blue]  
Mutable Set: [1, 2, 3]  
Hash Set: [Apple, Cherry, Banana]  
Linked Set: [First, Second, Third]  
Sorted Set: [1, 3, 5, 7, 9]  
  
2. Set Operations:  
After adding elements: [1, 2, 3, 4, 5, 6, 7]  
After removing elements: [2, 3, 4, 5]  
Contains 3: true  
Contains 10: false  
Set size: 4  
Is empty: false  
  
3. Mathematical Set Operations:  
Frontend: [HTML, CSS, JavaScript, React]  
Backend: [Kotlin, Java, Python, JavaScript]  
Union: [HTML, CSS, JavaScript, React, Kotlin, Java, Python]  
Intersection: [JavaScript]  
Frontend - Backend: [HTML, CSS, React]  
Symmetric Difference: [HTML, CSS, React, Kotlin, Java, Python]  
  
4. Functional Operations:  
Original: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  
Even numbers: [2, 4, 6, 8, 10]  
Squared numbers: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]  
Numbers > 5: [6, 7, 8, 9, 10]  
Sum: 55, Max: 10, Min: 1, Average: 5.5  
  
5. Student Course Management System:  
Alice's courses: [Kotlin Programming, Android Development, Data Structures & Algorithms]  
Bob's courses: [Kotlin Programming, Data Structures & Algorithms, Database Systems]  
Charlie's courses: [Android Development, Database Systems]  
Common courses (Alice & Bob): [Kotlin Programming, Data Structures & Algorithms]  
All courses: [Kotlin Programming, Android Development, Data Structures & Algorithms, Database Systems]  
Students in Kotlin course: [Alice, Bob]  
  
6. Performance Comparison:  
Performance for 10000 operations:  
HashSet: 15ms  
LinkedHashSet: 18ms  
TreeSet: 45ms  
  
Set sizes after operations:  
HashSet: 9876  
LinkedHashSet: 9823  
TreeSet: 9901