Back to path
BeginnerLexi · Project 1 of 12 ~3h· 5 milestones

Search it with a plain scan and measure the pain

You have a folder of text files and nothing to search them with.

Python type hintsModeling data as a list of tuplesWriting a correct linear searchHonest benchmarking with time.perf_counterReasoning about Big-O from measurementsDistinguishing algorithmic growth from noiseBuilding a tiny REPL/CLIReading docs.python.org for stdlib APIs

What you'll build

By the end you will have a working linear_search over an in-memory document list, a bench.py that times it honestly across a growing n, and a printed table showing the time roughly 10x-ing each time n does. You will be able to say why, in one sentence, and point at the numbers that prove it.

See how we teach, before you sign up

You don't just get code dumped on you. Every starter file and every solution is explained line-by-line, in plain English. Here's one real file from this project:

lexi/documents.pypython
"""Load Lexi's document set: a plain list of (doc_id, text) pairs."""
from __future__ import annotations

import pathlib


def load_documents(folder: str) -> list[tuple[int, str]]:
    """Read every .txt file in folder into memory as (doc_id, text)."""
    # TODO: list every *.txt path under folder, sorted for stable ids
    # TODO: read each file's text with encoding="utf-8"
    # TODO: append (doc_id, text) to docs
    raise NotImplementedError


def make_synthetic_documents(n: int) -> list[tuple[int, str]]:
    """Generate n fake documents so we can benchmark without real files."""
    # TODO: build a small vocabulary list to draw words from
    # TODO: for each doc_id in range(n), join words into one body string
    raise NotImplementedError

Reading this file

  • def load_documents(folder: str) -> list[tuple[int, str]]:Real documents come from a folder; each one becomes a (doc_id, text) tuple, the simplest shape that can hold a corpus.
  • # TODO: list every *.txt path under folder, sorted for stable idsSorting matters: without it, doc_id would depend on filesystem order, which can change between runs.
  • # TODO: read each file's text with encoding="utf-8"Always name the encoding explicitly, do not rely on the platform default.
  • raise NotImplementedErrorBoth functions start as stubs; you fill them in during milestone 1.

Represents the corpus as a plain list of (doc_id, text) tuples, nothing fancier. Also generates synthetic documents so you can benchmark at 100,000 without needing real files.

That's 1 of 7 explained code blocks in this single project.

The build, milestone by milestone

  1. 1

    Give it a document store

    4 guided steps

    Every rung after this one reuses this exact document shape, a list of (doc_id, text) tuples. Getting a clean, honest way to generate documents at any size now means every later benchmark is comparing apples to apples.

  2. 2

    Write the plain scan

    4 guided steps

    This is the correctness baseline every later rung (hash index, trie, sorted+binary search) will be judged against. If linear_search is wrong, a faster wrong answer is worthless, so nail correctness here with no shortcuts.

  3. 3

    Measure it honestly

    4 guided steps

    A benchmark you cannot trust is worse than no benchmark, it tells you a comforting story instead of the truth. The discipline here, warm the timer, repeat, grow n by orders of magnitude, carries forward unchanged to every future rung's benchmark.

  4. 4

    Reason about the O(n) shape before you trust the graph

    4 guided steps

    A benchmark alone can lie, machine noise, a background process, a JIT-like caching effect, anything. Big-O reasoning gives you a prediction to check the numbers against, so you catch a fluke benchmark instead of shipping a false conclusion.

  5. 5

    Package it as a tiny CLI and capture the pain

    4 guided steps

    Numbers in a table are convincing, a laggy REPL response is visceral. This milestone turns 'O(n) is technically slower' into 'I can feel every keystroke wait', which is exactly the pain that motivates the hash index in the next rung.

What's inside when you start

3 starter files, ready to clone
5 guided milestones
4 full reference solutions
7 code blocks explained line-by-line
5 "is it working?" checks
4 interview questions it prepares you for

You'll walk away with

lexi/documents.py with a working load_documents and make_synthetic_documents
lexi/search.py with a correct linear_search and count_comparisons
bench.py that prints best= and per_doc= for n = 1,000 / 10,000 / 100,000
lexi_cli.py, a small REPL that shows real elapsed milliseconds per query
A one-paragraph note stating that linear_search is O(n) and the measured ratio that backs it up

This is portfolio-grade. Build it free.

Sign up to unlock every milestone step-by-step, the code skeletons, full reference solutions, and checkable tasks, with your progress saved as you build.

Start building