How to Implement row_number Window Function in Python

This code implements a SQL-style ROW_NUMBER() window function in pure Python, partitioning rows by a set of columns and ranking them within each partition by an ordered set of columns.

Medium Python 3.9+ Aug 9, 2026 Big data & Spark 17 views 0 copies

Python code

33 lines
Python 3.9+
from collections import defaultdict
import itertools


def row_number(rows, partition_by, order_by):
    partitions = defaultdict(list)
    for index, row in enumerate(rows):
        key = tuple(row[col] for col in partition_by)
        partitions[key].append((index, row))

    result = []
    for key in partitions:
        partition_rows = partitions[key]
        partition_rows.sort(key=lambda item: tuple(item[1][col] for col in order_by))
        for rank, (index, row) in enumerate(partition_rows, start=1):
            result.append((index, rank, row))
    result.sort(key=lambda item: item[0])

    return [(rank, row) for index, rank, row in result]


if __name__ == "__main__":
    data = [
        {"dept": "sales", "emp": "Alice", "salary": 5000},
        {"dept": "sales", "emp": "Bob", "salary": 6000},
        {"dept": "hr", "emp": "Carol", "salary": 4000},
        {"dept": "hr", "emp": "Dave", "salary": 4500},
        {"dept": "sales", "emp": "Eve", "salary": 5500},
    ]

    ranked = row_number(data, partition_by=["dept"], order_by=["salary"])
    for rank, row in ranked:
        print(row["dept"], row["emp"], row["salary"], rank)

Output

stdout
sales Alice 5000 1
sales Eve 5500 2
sales Bob 6000 3
hr Carol 4000 1
hr Dave 4500 2

How it works

This implementation groups rows into partitions using a defaultdict keyed by the tuple of partition column values. Within each partition, rows are sorted by the order-by columns using a tuple of values for stable comparison. The enumerate function assigns a rank starting at 1 for each row in the sorted partition. Finally, results are collected and re-sorted by the original index to preserve input order. This approach mirrors SQL's ROW_NUMBER() semantics without any external dependencies, making it suitable for teaching or small-scale data processing.

Common mistakes

  • Forgetting to convert partition and order keys to tuples, which causes unhashable list errors.
  • Sorting the global result by rank instead of original index, losing input order.
  • Assuming stable sort without explicitly sorting by all order-by columns in the right direction.
  • Mutating the input rows list when partitioning causes unexpected behavior.

Variations

  1. Use pandas' groupby and cumcount to compute row_number more succinctly.
  2. Use itertools.groupby on sorted data to avoid a separate partition dictionary.

Real-world use cases

  • Assigning sequential numbers to customer orders per user before pagination or deduplication.
  • Ranking top N products per category in an e-commerce recommendation engine.
  • Implementing a lightweight analytics query in a Python service that avoids a full SQL engine.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Big data & Spark

Related tutorials and quizzes for this topic.