Card 05/ 09
Strategy in the Wild: Comparator in Java and sorted(key=) in Python
The sort is written once; the order is the strategy you pass it.
The sort functions of Java and Python are both contexts that take a strategy. The sorting algorithm is written once inside the library, and the caller passes in the part that varies: how two elements are ordered. This card sorts the same three books by title and then newest first in each language, and names the participant each piece plays.
The same books sorted two ways
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class StComparator {
record Book(String title, int year) {}
public static void main(String[] args) {
List<Book> books = new ArrayList<>(List.of(
new Book("Refactoring", 1999),
new Book("Design Patterns", 1994),
new Book("Clean Code", 2008)));
books.sort(Comparator.comparing(Book::title));
System.out.println("by title: " + books.stream().map(Book::title).toList());
books.sort(Comparator.comparingInt(Book::year).reversed());
System.out.println("newest first: " + books.stream().map(Book::title).toList());
}
}by title: [Clean Code, Design Patterns, Refactoring]
newest first: [Clean Code, Refactoring, Design Patterns]List.sort is the context. A Comparator is the strategy interface, with one method, compare(a, b), and each call to Comparator.comparing returns a concrete strategy. reversed() wraps one strategy in another that inverts it.
from typing import NamedTuple
class Book(NamedTuple):
title: str
year: int
books = [Book("Refactoring", 1999), Book("Design Patterns", 1994), Book("Clean Code", 2008)]
by_title = sorted(books, key=lambda book: book.title)
print("by title:", [book.title for book in by_title])
newest_first = sorted(books, key=lambda book: book.year, reverse=True)
print("newest first:", [book.title for book in newest_first])by title: ['Clean Code', 'Design Patterns', 'Refactoring']
newest first: ['Clean Code', 'Refactoring', 'Design Patterns']sorted is the context, and the function passed as key is the strategy. Python asks for a key rather than a comparison: it calls the function once per element and sorts by the results, which is simpler to write and faster than comparing pairs.
The two outputs agree, and so do the shapes. Neither library has a branch for titles or years; each was written long before these books existed, and orders them correctly because the caller supplied the one piece of knowledge it lacked.
What differs is the form of the strategy. Java needs an object that implements an interface, though a method reference such as Book::title lets the compiler build it. Python takes any function. In both, the library is closed to change and open to any order a caller can describe.
← → move through sections and cards