The Counting Machine

A medium Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.

Domain
Python
Difficulty
medium
Seniority
L4

Problem

Our batch scorer builds every position-weighted reading up front, where each reading is multiplied by its place in the batch, and we want those readings handed out one at a time instead. Implement CountUp over values as an iterator that produces the next weighted reading on each request and stops cleanly once the batch is exhausted, then have count_up(values) drive one to the end and return everything it produced, in order.

It knows where it stopped last time.

Example 1

Input:

values = [2,3,4]

Output:

[2,6,12]

Example 2

Input:

values = [10,0,-2,4]

Output:

[10,0,-6,16]

Worked solution and explanation

This is the iterator protocol with the safety net taken away. A generator or a comprehension ends on its own; a hand-written __next__ does not, and that is the whole test. Anyone can multiply a reading by its position. What separates candidates is the guard that raises StopIteration the moment the cursor passes the end, plus a weight that starts at one. Skip the guard and list(CountUp(values)) never gets a clean stop: it reads past the last element and dies with IndexError, so even the empty batch blows up. Use the raw 0-based cursor as the weight and the first reading is zeroed: [2, 3, 4] comes back as [0, 3, 8].

Building it

Step 1: Keep the batch and a cursor

__init__ stores values and sets self.index to 0. The cursor is the only state the iterator owns; it never copies or mutates the batch it was handed.

Step 2: Return self from __iter__

That makes CountUp its own iterator, so list() and a for loop can consume it directly without a separate iterator object.

Step 3: Guard before you read

The first line of __next__ compares self.index to len(self.values) and raises StopIteration once the cursor has run off the end. It has to come before the read: checked afterward, the empty batch already fails on self.values[0].

Step 4: Weight by self.index + 1, then advance

Compute the 1-based position, multiply, move the cursor, return. Advancing after the read keeps the cursor pointing at the next unread reading, so the guard on the next call sees the truth.

Step 5: Drive it from count_up

count_up(values) is one line: list(CountUp(values)). The class is what is being graded; the driver just gives the harness a function to call.

A top-level iterator class and its driver
class CountUp:
    def __init__(self, values):
        self.values = values
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index >= len(self.values):
            raise StopIteration
        position = self.index + 1
        weighted = self.values[self.index] * position
        self.index += 1
        return weighted


def count_up(values):
    return list(CountUp(values))
Generator function
A yield inside a loop over enumerate(values, start=1) stops when the loop stops; Python raises StopIteration on your behalf.
Hand-written iterator class
Nothing ends on its own. The class owns the cursor and must raise StopIteration itself, which is exactly the capability this problem checks.

Common follow-up questions