0
0
Kotlinprogramming~15 mins

For loop with index (withIndex) in Kotlin - Deep Dive

Choose your learning style9 modes available
Overview - For loop with index (withIndex)
What is it?
A for loop with index in Kotlin lets you go through each item in a list or array while also knowing the position of that item. The withIndex() function pairs each element with its index number, starting from zero. This helps when you want to do something special depending on where the item is in the list. It makes looping easier and clearer when you need both the item and its place.
Why it matters
Without a way to get the index while looping, you would have to manually track positions, which can cause mistakes and make code longer. Using withIndex() saves time and reduces errors by giving you both the item and its index automatically. This is useful in many real-life tasks, like numbering items in a list or matching positions to values, making your programs smarter and easier to read.
Where it fits
Before learning this, you should know basic Kotlin for loops and how to work with lists or arrays. After mastering for loops with index, you can explore more advanced collection operations like map, filter, and zip, or learn about Kotlin sequences for efficient data processing.
Mental Model
Core Idea
withIndex() pairs each item with its position so you can loop over both together easily.
Think of it like...
Imagine you have a row of mailboxes numbered from 0 upwards, and you want to check each mailbox and know its number at the same time. withIndex() is like walking down the row, holding a list of mailbox numbers paired with their contents.
List: [apple, banana, cherry]

withIndex() pairs:
┌─────┬────────┐
│ idx │ value  │
├─────┼────────┤
│  0  │ apple  │
│  1  │ banana │
│  2  │ cherry │
└─────┴────────┘

Loop:
for ((idx, value) in list.withIndex()) {
  // use idx and value
}
Build-Up - 7 Steps
1
FoundationBasic for loop over list
🤔
Concept: Learn how to loop through each item in a list using a simple for loop.
val fruits = listOf("apple", "banana", "cherry") for (fruit in fruits) { println(fruit) }
Result
apple banana cherry
Understanding how to loop over items is the first step before adding index tracking.
2
FoundationUnderstanding list indices
🤔
Concept: Learn that each item in a list has a position number called an index, starting at zero.
val fruits = listOf("apple", "banana", "cherry") println(fruits[0]) // apple println(fruits[1]) // banana println(fruits[2]) // cherry
Result
apple banana cherry
Knowing that lists have positions helps you understand why you might want the index during looping.
3
IntermediateUsing withIndex() in for loop
🤔
Concept: Introduce withIndex() to get both index and value while looping.
val fruits = listOf("apple", "banana", "cherry") for ((index, fruit) in fruits.withIndex()) { println("Item $index is $fruit") }
Result
Item 0 is apple Item 1 is banana Item 2 is cherry
withIndex() simplifies getting the position and item together without manual counting.
4
IntermediateDestructuring declaration in loops
🤔
Concept: Learn how Kotlin lets you unpack pairs like (index, value) directly in the loop header.
for ((index, fruit) in fruits.withIndex()) { println("Index: $index, Fruit: $fruit") }
Result
Index: 0, Fruit: apple Index: 1, Fruit: banana Index: 2, Fruit: cherry
Destructuring makes code cleaner and easier to read by unpacking pairs automatically.
5
IntermediateManual index tracking vs withIndex()
🤔Before reading on: Do you think manually tracking index is simpler or more error-prone than using withIndex()? Commit to your answer.
Concept: Compare manual index counting with the automatic withIndex() method.
val fruits = listOf("apple", "banana", "cherry") var index = 0 for (fruit in fruits) { println("Item $index is $fruit") index++ }
Result
Item 0 is apple Item 1 is banana Item 2 is cherry
Using withIndex() avoids mistakes like forgetting to increment the index and makes code shorter.
6
AdvancedUsing withIndex() with arrays and other collections
🤔Before reading on: Do you think withIndex() works only with lists or also with arrays and other collections? Commit to your answer.
Concept: Learn that withIndex() works with arrays, lists, and other iterable collections.
val numbers = arrayOf(10, 20, 30) for ((i, num) in numbers.withIndex()) { println("Index $i has value $num") }
Result
Index 0 has value 10 Index 1 has value 20 Index 2 has value 30
Knowing withIndex() works broadly lets you use it in many situations without extra code.
7
ExpertPerformance and internal behavior of withIndex()
🤔Before reading on: Do you think withIndex() creates a new list or just a view when called? Commit to your answer.
Concept: Understand that withIndex() creates a lazy sequence of indexed values, not a full new list.
When you call withIndex(), Kotlin creates an iterator that pairs each element with its index on the fly. It does not copy the whole collection, so it is efficient even for large data.
Result
Efficient looping with index without extra memory use.
Understanding lazy pairing helps avoid performance surprises in large or infinite collections.
Under the Hood
The withIndex() function returns a sequence of IndexedValue objects, each holding an index and the corresponding element. When you loop over this sequence, Kotlin uses an iterator that generates each IndexedValue one by one, pairing the current index with the element. This avoids creating a full new list and keeps memory use low.
Why designed this way?
Kotlin's designers wanted a simple, readable way to get both index and value without extra code or manual counting. Using a lazy iterator avoids performance costs of copying collections. This design balances ease of use with efficiency, unlike older approaches that required manual index tracking or creating new lists.
Original collection
  │
  ▼
withIndex() creates iterator
  │
  ▼
Iterator yields IndexedValue(index, value)
  │
  ▼
for loop destructures (index, value)
  │
  ▼
User code uses index and value
Myth Busters - 4 Common Misconceptions
Quick: Does withIndex() create a new list in memory or just a view? Commit to your answer.
Common Belief:withIndex() creates a full new list of pairs, so it uses extra memory.
Tap to reveal reality
Reality:withIndex() returns a lazy iterator that generates pairs on demand without copying the whole collection.
Why it matters:Thinking it creates a new list might scare you away from using it on large collections, missing out on its efficiency.
Quick: Can you modify the original list elements safely while looping with withIndex()? Commit to your answer.
Common Belief:You can change list items safely during a withIndex() loop without issues.
Tap to reveal reality
Reality:Modifying the collection while iterating can cause errors or unexpected behavior because the iterator expects the collection to stay stable.
Why it matters:Ignoring this can cause runtime exceptions or bugs that are hard to trace.
Quick: Does the index from withIndex() always start at 1? Commit to your answer.
Common Belief:The index from withIndex() starts at 1 because counting usually starts at one.
Tap to reveal reality
Reality:The index always starts at 0, following Kotlin's zero-based indexing convention.
Why it matters:Assuming it starts at 1 can cause off-by-one errors in your code.
Quick: Is destructuring required to use withIndex()? Commit to your answer.
Common Belief:You must always destructure the pair to use withIndex().
Tap to reveal reality
Reality:You can use the pair as a single object and access index and value via properties if you prefer.
Why it matters:Knowing this gives flexibility in how you write your loops.
Expert Zone
1
withIndex() returns an IndexedValue sequence that is lazy, so it does not create intermediate collections, which is important for performance in large data sets.
2
Destructuring in the for loop is syntactic sugar; under the hood, it accesses properties of IndexedValue, which can be used directly if needed.
3
Using withIndex() with sequences preserves laziness, but using it with collections like lists or arrays creates an eager iterator; understanding this helps optimize code.
When NOT to use
Avoid withIndex() when you only need the values without their positions, as it adds unnecessary overhead. For very large or infinite sequences where you only need some elements, consider using indexed sequences carefully to avoid performance hits. If you need custom index logic (like starting from 1 or skipping numbers), manual tracking or mapIndexed might be better.
Production Patterns
In real-world Kotlin code, withIndex() is commonly used for logging item positions, numbering output lines, or synchronizing parallel lists. It is also used in UI code to bind data with positions, such as in RecyclerView adapters. Experts combine withIndex() with other collection functions like filterIndexed or mapIndexed for concise, readable transformations.
Connections
Enumerate in Python
Similar pattern providing index and value pairs during iteration.
Knowing Kotlin's withIndex() helps understand Python's enumerate, showing a common solution across languages for indexed loops.
Zip function
Both create pairs during iteration, but zip combines two collections, while withIndex() pairs items with their position.
Understanding withIndex() clarifies how pairing works in iteration, which helps grasp zip's behavior.
Assembly language indexing
Both involve tracking positions explicitly, but withIndex() automates this in high-level code.
Seeing how low-level code manages indexes manually highlights the convenience and safety of withIndex() in Kotlin.
Common Pitfalls
#1Forgetting to destructure the pair and trying to use it as a single variable.
Wrong approach:for (item in list.withIndex()) { println("Index: $item, Value: $item") }
Correct approach:for ((index, value) in list.withIndex()) { println("Index: $index, Value: $value") }
Root cause:Not realizing withIndex() returns a pair object that needs unpacking to access index and value separately.
#2Manually tracking index with a separate variable instead of using withIndex().
Wrong approach:var i = 0 for (item in list) { println("Index: $i, Value: $item") i++ }
Correct approach:for ((i, item) in list.withIndex()) { println("Index: $i, Value: $item") }
Root cause:Not knowing withIndex() exists leads to more error-prone and verbose code.
#3Modifying the list inside a withIndex() loop causing runtime errors.
Wrong approach:for ((i, item) in list.withIndex()) { list.removeAt(i) }
Correct approach:val copy = list.toList() for ((i, item) in copy.withIndex()) { list.removeAt(i) }
Root cause:Misunderstanding that modifying a collection during iteration invalidates the iterator.
Key Takeaways
withIndex() in Kotlin lets you loop over a collection while automatically getting each item's position.
It returns a lazy sequence of pairs, so it is efficient and does not copy the whole collection.
Destructuring declarations make it easy to access index and value in the loop header.
Using withIndex() avoids manual index tracking, reducing bugs and making code cleaner.
Understanding how withIndex() works helps write better, more readable Kotlin loops and avoid common mistakes.