Kotlin List

A Kotlin list is a generic, ordered collection interface that stores elements in a specific sequence. Lists maintain insertion order and allow duplicate elements, making them perfect for scenarios where element position matters. The List interface in Kotlin extends the Collection interface and provides indexed access to elements, starting from index 0.

// Basic list structure
val numbers: List<Int> = listOf(1, 2, 3, 4, 5)
val firstElement = numbers[0] // Access by index
val listSize = numbers.size   // Get list size

Key Characteristics of Kotlin Lists

Ordered Collection: Elements maintain their insertion order, ensuring predictable iteration and access patterns.

Index-Based Access: Elements can be accessed directly using their zero-based index position.

Duplicate Elements Allowed: Unlike sets, lists can contain multiple instances of the same element.

Type Safety: Kotlin’s type system ensures compile-time safety when working with list elements.

Creating Immutable Lists with listOf()

Basic listOf() Usage

The listOf() function creates read-only lists that cannot be modified after creation. This immutability provides thread safety and prevents accidental modifications that could lead to bugs.

// Creating different types of immutable lists
val fruits = listOf("apple", "banana", "orange")
val primes = listOf(2, 3, 5, 7, 11)
val mixedTypes = listOf("text", 42, true, 3.14)
val emptyList = listOf<String>() // Empty typed list

Advanced listOf() Patterns

Null Handling with listOfNotNull():

val validItems = listOfNotNull("item1", null, "item3", null, "item5")
// Result: ["item1", "item3", "item5"]

Creating Lists with Repeated Elements:

val repeatedElements = List(5) { "default" }
// Result: ["default", "default", "default", "default", "default"]

List Creation with Lambda Initialization:

val squaredNumbers = List(10) { index -> index * index }
// Result: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Working with Mutable Lists using mutableListOf()

Creating and Modifying Mutable Lists

MutableListOf() creates lists that support add, remove, and update operations. These lists implement the MutableList interface, providing full read-write capabilities.

// Creating mutable lists
val cities = mutableListOf("New York", "London", "Tokyo")
val numbers = mutableListOf<Int>() // Empty mutable list
val mixedData = mutableListOf<Any>("text", 123, true)

Essential Mutable List Operations

Adding Elements:

val shoppingList = mutableListOf("milk", "bread")
shoppingList.add("eggs")                    // Add at end
shoppingList.add(1, "butter")              // Add at specific index
shoppingList.addAll(listOf("cheese", "ham")) // Add multiple elements
shoppingList += "yogurt"                   // Operator overloading

Removing Elements:

val items = mutableListOf("a", "b", "c", "d", "b")
items.remove("b")           // Removes first occurrence
items.removeAt(2)          // Remove by index
items.removeAll(listOf("a", "c")) // Remove multiple elements
items.clear()              // Remove all elements

Updating Elements:

val scores = mutableListOf(85, 92, 78, 96)
scores[1] = 95            // Update using index operator
scores.set(3, 100)        // Update using set method
scores.fill(0)            // Replace all elements with same value

Essential List Access Methods

Element Retrieval Techniques

Safe Access Methods:

val languages = listOf("Kotlin", "Java", "Swift", "Python")

// Safe access with bounds checking
val first = languages.getOrNull(0)      // Returns "Kotlin" or null
val invalid = languages.getOrNull(10)   // Returns null
val withDefault = languages.getOrElse(5) { "Unknown" } // Returns "Unknown"

First and Last Element Access:

val scores = listOf(88, 92, 78, 96, 85)
val highest = scores.first()             // First element: 88
val lowest = scores.last()               // Last element: 85
val firstHigh = scores.first { it > 90 } // First element > 90: 92
val lastHigh = scores.lastOrNull { it > 100 } // null (no element > 100)

Index Operations

Finding Element Positions:

val colors = listOf("red", "blue", "green", "blue", "yellow")
val firstBlue = colors.indexOf("blue")        // Returns 1
val lastBlue = colors.lastIndexOf("blue")     // Returns 3
val notFound = colors.indexOf("purple")       // Returns -1

// Conditional index finding
val firstLongColor = colors.indexOfFirst { it.length > 4 }  // Index of "green"
val lastLongColor = colors.indexOfLast { it.length > 4 }    // Index of "yellow"

Advanced List Transformation Methods

Mapping and Filtering Operations

Transform Elements with map():

val temperatures = listOf(20, 25, 30, 35)
val fahrenheit = temperatures.map { celsius -> celsius * 9/5 + 32 }
// Result: [68, 77, 86, 95]

val names = listOf("john", "alice", "bob")
val capitalized = names.map { it.replaceFirstChar { char -> char.uppercase() } }
// Result: ["John", "Alice", "Bob"]

Filter Elements with Conditions:

val ages = listOf(16, 25, 19, 30, 15, 28)
val adults = ages.filter { it >= 18 }           // [25, 19, 30, 28]
val minors = ages.filterNot { it >= 18 }        // [16, 15]
val evenAges = ages.filter { it % 2 == 0 }      // [16, 30, 28]

Partitioning and Grouping

Partition Elements:

val grades = listOf(85, 92, 67, 88, 91, 73, 96)
val (passing, failing) = grades.partition { it >= 75 }
// passing: [85, 92, 88, 91, 96], failing: [67, 73]

Group by Criteria:

val students = listOf("Alice", "Bob", "Charlie", "Diana", "Alex")
val byFirstLetter = students.groupBy { it.first() }
// Result: {A=[Alice, Alex], B=[Bob], C=[Charlie], D=[Diana]}

List Slicing and Sublist Operations

Creating Sublists

Using take() and drop() Methods:

val fibonacci = listOf(1, 1, 2, 3, 5, 8, 13, 21, 34)
val firstFive = fibonacci.take(5)           // [1, 1, 2, 3, 5]
val lastFour = fibonacci.takeLast(4)        // [8, 13, 21, 34]
val skipFirst = fibonacci.drop(2)           // [2, 3, 5, 8, 13, 21, 34]
val skipLast = fibonacci.dropLast(3)        // [1, 1, 2, 3, 5, 8]

Conditional Taking and Dropping:

val numbers = listOf(1, 3, 5, 8, 10, 12, 15)
val takeWhileOdd = numbers.takeWhile { it % 2 == 1 }  // [1, 3, 5]
val dropWhileOdd = numbers.dropWhile { it % 2 == 1 }  // [8, 10, 12, 15]

Range-based Sublists:

val alphabet = listOf('a', 'b', 'c', 'd', 'e', 'f', 'g')
val middleSection = alphabet.subList(2, 5)  // [c, d, e]
val sliceRange = alphabet.slice(1..4)       // [b, c, d, e]
val specificIndices = alphabet.slice(listOf(0, 2, 4, 6)) // [a, c, e, g]

List Sorting and Ordering

Sorting Immutable Lists

Basic Sorting Operations:

val unsorted = listOf(42, 17, 89, 23, 56)
val ascending = unsorted.sorted()           // [17, 23, 42, 56, 89]
val descending = unsorted.sortedDescending() // [89, 56, 42, 23, 17]

val words = listOf("elephant", "cat", "butterfly", "dog")
val byLength = words.sortedBy { it.length }  // [cat, dog, elephant, butterfly]
val byLengthDesc = words.sortedByDescending { it.length } // [butterfly, elephant, cat, dog]

In-Place Sorting for Mutable Lists

Modifying Original List:

val mutableScores = mutableListOf(88, 72, 95, 81, 90)
mutableScores.sort()                    // Sorts in-place: [72, 81, 88, 90, 95]
mutableScores.sortDescending()          // [95, 90, 88, 81, 72]

val mutableNames = mutableListOf("Zoe", "Alice", "Bob", "Charlie")
mutableNames.sortBy { it.length }       // Sort by length in-place
mutableNames.sortWith(compareBy { it.lowercase() }) // Custom comparator

List Aggregation and Statistical Operations

Mathematical Operations

Basic Statistics:

val values = listOf(10, 25, 30, 15, 40, 35, 20)
val total = values.sum()               // 175
val average = values.average()         // 25.0
val maximum = values.maxOrNull()       // 40
val minimum = values.minOrNull()       // 10
val count = values.count()             // 7

Custom Aggregation with reduce() and fold():

val numbers = listOf(1, 2, 3, 4, 5)
val product = numbers.reduce { acc, n -> acc * n }    // 120
val concatenated = numbers.fold("") { acc, n -> acc + n } // "12345"

// Finding custom maximum
data class Product(val name: String, val price: Double)
val products = listOf(
    Product("Laptop", 999.99),
    Product("Mouse", 29.99), 
    Product("Keyboard", 79.99)
)
val mostExpensive = products.maxByOrNull { it.price } // Laptop

Converting Between List Types

Transformation Methods

Converting to Different List Types:

val originalList = listOf(1, 2, 3, 4, 5)
val mutableCopy = originalList.toMutableList()
val immutableCopy = mutableCopy.toList()
val arrayList = originalList.toCollection(ArrayList())
val linkedList = originalList.toCollection(LinkedList())

Type Conversion:

val strings = listOf("1", "2", "3", "4", "5")
val integers = strings.map { it.toInt() }           // Convert to Int
val doubled = strings.mapNotNull { it.toIntOrNull()?.times(2) } // Safe conversion

// Converting to other collections
val setFromList = originalList.toSet()              // Remove duplicates
val arrayFromList = originalList.toTypedArray()     // Convert to Array

Complete Working Examples

Example 1: Student Grade Management System

data class Student(val name: String, val grades: MutableList<Int>)

fun main() {
    // Initialize students with grades
    val students = mutableListOf(
        Student("Alice", mutableListOf(85, 92, 78, 88)),
        Student("Bob", mutableListOf(79, 84, 91, 77)),
        Student("Charlie", mutableListOf(92, 88, 94, 90))
    )
    
    // Add new grade for Alice
    students[0].grades.add(95)
    
    // Calculate averages for each student
    val studentAverages = students.map { student ->
        student.name to student.grades.average()
    }
    
    // Find top performing student
    val topStudent = students.maxByOrNull { it.grades.average() }
    
    // Filter students with average above 85
    val highPerformers = students.filter { it.grades.average() > 85.0 }
    
    // Print results
    println("Student Averages:")
    studentAverages.forEach { (name, avg) ->
        println("$name: ${String.format("%.2f", avg)}")
    }
    
    println("\nTop Student: ${topStudent?.name}")
    println("High Performers: ${highPerformers.map { it.name }}")
}

/* Expected Output:
Student Averages:
Alice: 87.60
Bob: 82.75
Charlie: 91.00

Top Student: Charlie
High Performers: [Alice, Charlie]
*/

Example 2: E-commerce Shopping Cart Implementation

data class Product(val id: Int, val name: String, val price: Double)
data class CartItem(val product: Product, var quantity: Int)

class ShoppingCart {
    private val items = mutableListOf<CartItem>()
    
    fun addProduct(product: Product, quantity: Int = 1) {
        val existingItem = items.find { it.product.id == product.id }
        if (existingItem != null) {
            existingItem.quantity += quantity
        } else {
            items.add(CartItem(product, quantity))
        }
    }
    
    fun removeProduct(productId: Int) {
        items.removeAll { it.product.id == productId }
    }
    
    fun updateQuantity(productId: Int, newQuantity: Int) {
        items.find { it.product.id == productId }?.quantity = newQuantity
    }
    
    fun getTotalPrice(): Double = items.sumOf { it.product.price * it.quantity }
    
    fun getItems(): List<CartItem> = items.toList() // Return immutable view
    
    fun getItemCount(): Int = items.sumOf { it.quantity }
    
    fun getMostExpensiveItem(): CartItem? = items.maxByOrNull { it.product.price }
    
    fun filterByPriceRange(minPrice: Double, maxPrice: Double): List<CartItem> {
        return items.filter { it.product.price in minPrice..maxPrice }
    }
}

fun main() {
    val cart = ShoppingCart()
    
    // Sample products
    val laptop = Product(1, "Gaming Laptop", 1299.99)
    val mouse = Product(2, "Wireless Mouse", 79.99)
    val keyboard = Product(3, "Mechanical Keyboard", 149.99)
    val monitor = Product(4, "4K Monitor", 399.99)
    
    // Add products to cart
    cart.addProduct(laptop, 1)
    cart.addProduct(mouse, 2)
    cart.addProduct(keyboard, 1)
    cart.addProduct(monitor, 1)
    
    // Update quantity
    cart.updateQuantity(2, 3) // Change mouse quantity to 3
    
    // Display cart information
    println("Shopping Cart Contents:")
    cart.getItems().forEach { item ->
        val total = item.product.price * item.quantity
        println("${item.product.name} x ${item.quantity} = $${String.format("%.2f", total)}")
    }
    
    println("\nCart Summary:")
    println("Total Items: ${cart.getItemCount()}")
    println("Total Price: $${String.format("%.2f", cart.getTotalPrice())}")
    
    val mostExpensive = cart.getMostExpensiveItem()
    println("Most Expensive Item: ${mostExpensive?.product?.name}")
    
    // Filter affordable items (under $200)
    val affordableItems = cart.filterByPriceRange(0.0, 200.0)
    println("\nAffordable Items (under $200):")
    affordableItems.forEach { item ->
        println("- ${item.product.name}: $${item.product.price}")
    }
}

/* Expected Output:
Shopping Cart Contents:
Gaming Laptop x 1 = $1299.99
Wireless Mouse x 3 = $239.97
Mechanical Keyboard x 1 = $149.99
4K Monitor x 1 = $399.99

Cart Summary:
Total Items: 6
Total Price: $2089.94
Most Expensive Item: Gaming Laptop

Affordable Items (under $200):
- Wireless Mouse: $79.99
- Mechanical Keyboard: $149.99
*/

Example 3: Data Processing Pipeline

data class Transaction(
    val id: String,
    val amount: Double,
    val category: String,
    val date: String,
    val isCredit: Boolean
)

fun main() {
    // Sample transaction data
    val transactions = listOf(
        Transaction("T001", 1200.00, "Salary", "2024-01-15", true),
        Transaction("T002", 85.50, "Groceries", "2024-01-16", false),
        Transaction("T003", 45.00, "Gas", "2024-01-17", false),
        Transaction("T004", 1500.00, "Freelance", "2024-01-18", true),
        Transaction("T005", 120.00, "Utilities", "2024-01-19", false),
        Transaction("T006", 250.00, "Shopping", "2024-01-20", false),
        Transaction("T007", 800.00, "Bonus", "2024-01-21", true),
        Transaction("T008", 95.75, "Groceries", "2024-01-22", false)
    )
    
    // Separate credits and debits
    val (credits, debits) = transactions.partition { it.isCredit }
    
    // Calculate totals
    val totalIncome = credits.sumOf { it.amount }
    val totalExpenses = debits.sumOf { it.amount }
    val netBalance = totalIncome - totalExpenses
    
    // Group expenses by category
    val expensesByCategory = debits.groupBy { it.category }
        .mapValues { (_, transactions) -> transactions.sumOf { it.amount } }
        .toList()
        .sortedByDescending { it.second }
    
    // Find largest transactions
    val largestCredit = credits.maxByOrNull { it.amount }
    val largestDebit = debits.maxByOrNull { it.amount }
    
    // Filter high-value transactions (over $100)
    val highValueTransactions = transactions.filter { it.amount > 100.0 }
        .sortedByDescending { it.amount }
    
    // Generate expense categories list
    val uniqueCategories = debits.map { it.category }.distinct().sorted()
    
    // Print financial summary
    println("=== FINANCIAL SUMMARY ===")
    println("Total Income: $${String.format("%.2f", totalIncome)}")
    println("Total Expenses: $${String.format("%.2f", totalExpenses)}")
    println("Net Balance: $${String.format("%.2f", netBalance)}")
    
    println("\n=== EXPENSES BY CATEGORY ===")
    expensesByCategory.forEach { (category, amount) ->
        println("$category: $${String.format("%.2f", amount)}")
    }
    
    println("\n=== LARGEST TRANSACTIONS ===")
    println("Largest Credit: ${largestCredit?.let { "${it.category} - $${it.amount}" }}")
    println("Largest Debit: ${largestDebit?.let { "${it.category} - $${it.amount}" }}")
    
    println("\n=== HIGH-VALUE TRANSACTIONS (>$100) ===")
    highValueTransactions.forEach { transaction ->
        val type = if (transaction.isCredit) "Credit" else "Debit"
        println("${transaction.date}: $type - ${transaction.category} - $${transaction.amount}")
    }
    
    println("\n=== EXPENSE CATEGORIES ===")
    println("Categories: ${uniqueCategories.joinToString(", ")}")
    
    println("\n=== TRANSACTION STATISTICS ===")
    println("Total Transactions: ${transactions.size}")
    println("Credit Transactions: ${credits.size}")
    println("Debit Transactions: ${debits.size}")
    println("Average Transaction Amount: $${String.format("%.2f", transactions.map { it.amount }.average())}")
}

/* Expected Output:
=== FINANCIAL SUMMARY ===
Total Income: $3500.00
Total Expenses: $596.25
Net Balance: $2903.75

=== EXPENSES BY CATEGORY ===
Shopping: $250.00
Groceries: $181.25
Utilities: $120.00
Gas: $45.00

=== LARGEST TRANSACTIONS ===
Largest Credit: Freelance - $1500.0
Largest Debit: Shopping - $250.0

=== HIGH-VALUE TRANSACTIONS (>$100) ===
2024-01-18: Credit - Freelance - $1500.0
2024-01-15: Credit - Salary - $1200.0
2024-01-21: Credit - Bonus - $800.0
2024-01-20: Debit - Shopping - $250.0
2024-01-19: Debit - Utilities - $120.0

=== EXPENSE CATEGORIES ===
Categories: Gas, Groceries, Shopping, Utilities

=== TRANSACTION STATISTICS ===
Total Transactions: 8
Credit Transactions: 3
Debit Transactions: 5
Average Transaction Amount: $512.03
*/