Start learning free

LESSON 276 OF 677 · TUPLES, SORTING & BUILT-INS

Price List in Scala: Combining zip and zipWithIndex

Practice Read the full explanation

You get an ArrayBuffer of strings items and an ArrayBuffer of integers prices. Return an ArrayBuffer of strings with one line per item.

The price at each index belongs to the item at the same index.

A line looks like "1. apple: 3". It has the item's number, then the item, then its price.

The numbers start at 1. The lines keep the order of items.

 

Example 1:

Input: items = ["apple", "bread", "milk"], prices = [3, 2, 4]
Output: ["1. apple: 3", "2. bread: 2", "3. milk: 4"]
Explanation: The apple is first and costs 3.
The bread is second and costs 2.
The milk is third and costs 4.

Example 2:

Input: items = ["tea"], prices = [5]
Output: ["1. tea: 5"]
Explanation: One item gives one line, number 1.

Example 3:

Input: items = ["pen", "pen", "ink"], prices = [2, 3, 0]
Output: ["1. pen: 2", "2. pen: 3", "3. ink: 0"]
Explanation: The shop sells two kinds of pen.
Each one gets its own line, number and price.
The ink is free, so its price is 0.

 

Constraints:

  • items and prices have the same length.
  • They have 1 to 100 entries.
  • Each item is one word of lowercase letters.
  • Each price is a whole number from 0 to 1000.
STEP 1 OF 4
    Ctrl + Enter to check

    SCALA · TUPLES, SORTING & BUILT-INS

    Price List in Scala, explained

    Problem overview

    priceList gets an ArrayBuffer[String] of items and an ArrayBuffer[Int] of prices. Both have the same length, from 1 to 100 entries, and the price at each index belongs to the item at the same index. It returns an ArrayBuffer[String] with one line per item, like "1. apple: 3": the item's number, a dot and a space, the item, a colon and a space, and the price. Numbers start at 1 and the lines keep the order of items.

    • ["apple", "bread", "milk"] with [3, 2, 4] gives ["1. apple: 3", "2. bread: 2", "3. milk: 4"].
    • ["tea"] with [5] gives ["1. tea: 5"].
    • ["pen", "pen", "ink"] with [2, 3, 0] gives ["1. pen: 2", "2. pen: 3", "3. ink: 0"]. Both pens get their own line, and the free ink has price 0.

    Approach

    Each line needs three things: an item, its price and a number. The item and the price sit at the same position in two buffers, which is what zip pairs up. The number is the position plus one, which is what zipWithIndex adds. Chain them, and one loop sees everything it needs on each pass.

    The index starts at 0 and the numbers must start at 1, so the line uses i + 1.

    Step by step

    1. Start with an empty ArrayBuffer[String]() named lines.
    2. Loop over items.zip(prices).zipWithIndex. Each element is a pair of a pair and an index, so the loop pattern is ((item, price), i).
    3. Inside, add the line with +=, using an s"..." string: ${i + 1}, a dot and a space, item, a colon and a space, price.
    4. After the loop, return lines.

    The solution in Scala

    class Solution {
        def priceList(items: ArrayBuffer[String], prices: ArrayBuffer[Int]): ArrayBuffer[String] = {
            val lines = ArrayBuffer[String]()
            for (((item, price), i) <- items.zip(prices).zipWithIndex) {
                lines += s"${i + 1}. $item: $price"
            }
            return lines
        }
    }
    

    What items.zip(prices).zipWithIndex builds for the first example is ArrayBuffer(((apple,3),0), ((bread,2),1), ((milk,4),2)). The nesting in the loop pattern follows it: the pair is inside, and the index is outside and second. A flat pattern like (item, price, i) would not match this shape.

    In the string, ${i + 1} is needed for the arithmetic, because a plain $i only inserts a name. The other parts, $item and $price, are single names, so they need no braces.

    The lines keep the order of items because zip and zipWithIndex both walk the buffers from the first position to the last. The lengths match, as the statement promises, so no price is cut off by zip. If the lengths could differ, the shorter buffer would decide how many lines you get.

    Testing

    ["apple", "bread", "milk"], [3, 2, 4]   ArrayBuffer(1. apple: 3, 2. bread: 2, 3. milk: 4)
    ["tea"], [5]                            ArrayBuffer(1. tea: 5)
    ["pen", "pen", "ink"], [2, 3, 0]        ArrayBuffer(1. pen: 2, 2. pen: 3, 3. ink: 0)
    

    Another way

    You can also loop over the index and read both buffers: for (i <- items.indices) with items(i) and prices(i). It gives the same lines, but the pairs make it harder to read the wrong position. Another form skips the loop: items.zip(prices).map { case (item, price) => s"$item: $price" } builds the lines without numbers.

    Common mistakes

    • Printing the index as is. The first line would start with 0. instead of 1..
    • Putting the index first in the pattern. zipWithIndex gives the item first and the index second. With the names swapped, the line text comes out wrong.
    • Dropping a repeated item. Two pens get two lines, because each line comes from a position, not from the item's name.
    • Returning inside the loop. Return after the loop, once every line has been added.
    Keep going with Scala500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free