Problem overview
priceList receives a list of strings items and a list of integers prices of the same length. The price at each index belongs to the item at the same index. It returns one line per item, like "1. apple: 3": the item's number (starting at 1), a dot and a space, the item, a colon and a space, then the price. The lines keep the order of items.
For ["apple", "bread", "milk"] and [3, 2, 4] the lines are 1. apple: 3, 2. bread: 2 and 3. milk: 4. For ["pen", "pen", "ink"] and [2, 3, 0] each pen gets its own line, because the lines are matched by position: 1. pen: 2, 2. pen: 3, 3. ink: 0.
Approach
Two things are needed for each line: the item with its price, and the item's number. items.zip(prices) gives the first, a list of pairs (item, price). withIndex() adds the second, the position from 0. Chained, items.zip(prices).withIndex() gives an index and a pair on each pass. The index starts at 0, so the line number is i + 1.
Step by step
- Make an empty
mutableListOf<String>()namedlines. - Loop with
for ((i, pair) in items.zip(prices).withIndex()). The loop variablepairis the pair of item and price. - Unpack it inside the loop:
val (item, price) = pair. Aforline can't unpack a pair inside a pair, so this step is a separate line. - Add the line to
lineswith a string template:"${i + 1}. $item: $price". - After the loop, return
lines.
The solution in Kotlin
class Solution {
fun priceList(items: List<String>, prices: List<Int>): List<String> {
val lines = mutableListOf<String>()
for ((i, pair) in items.zip(prices).withIndex()) {
val (item, price) = pair
lines.add("${i + 1}. $item: $price")
}
return lines
}
}
On the three examples it returns:
[1. apple: 3, 2. bread: 2, 3. milk: 4]
[1. tea: 5]
[1. pen: 2, 2. pen: 3, 3. ink: 0]
(Kotlin prints a list with brackets and commas; each element is one line of the result.)
What each piece holds
For the first example, items.zip(prices) is [(apple, 3), (bread, 2), (milk, 4)]. Adding withIndex() numbers those pairs from 0, so the loop sees index 0 with the pair for apple, index 1 with the pair for bread, and index 2 with the pair for milk. On each pass, item and price come from unpacking that pass's pair, and the line is built from the three values. A single item, as in the second example, makes the loop run once and produce 1. tea: 5.
Details worth knowing
The string template needs ${i + 1} in braces because it is an expression. A plain $item works for a single variable name. Writing $i + 1 inside the string would insert the index and then the plain text + 1, giving 0 + 1. apple: 3 for the first line.
Because the lengths are equal, zip loses nothing. If they weren't, zip would stop at the shorter list without an error.
Another way
The loop and the lines list can be replaced by mapIndexed, which calls a lambda with the index and each pair, and collects the results. The lambda can unpack the pair in its own parameters:
val lines = items.zip(prices).mapIndexed { i, (item, price) -> "${i + 1}. $item: $price" }
It gives the same result, [1. apple: 3, 2. bread: 2, 3. milk: 4], for the first example. The loop version is the one the lesson builds, and it keeps every step visible.
Edge cases and common mistakes
- Numbering from 0. Printing
$igives0. apple: 3. Use${i + 1}. - Nested unpacking in the
forline.for ((i, (item, price)) in ...)doesn't compile; unpack the pair in the body. - Looking prices up by item. With repeated items such as the two pens, a lookup by name would find the wrong price. Matching by position is what keeps both lines right.
- Wrong separators. The tests compare the lines exactly: a dot and a space after the number, a colon and a space before the price.
