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