fluttersmith/py-snippetsGitHub ↗

List difference by a key

Keep the items of one list whose key doesn't appear in another, preserving order.

Lists#setsO(n + m) time✓ 3 examples pass on 3.11–3.14

set(a) - set(b) loses order and needs hashable items. This compares on a key instead, so it works for dicts and objects.

difference_by.py✓ ruff · mypy --strict
from collections.abc import Callable, Hashable, Iterable
from typing import TypeVar

T = TypeVar("T")
K = TypeVar("K", bound=Hashable)


def difference_by(a: Iterable[T], b: Iterable[T], key: Callable[[T], K]) -> list[T]:
    """Return the items of ``a`` whose ``key`` matches no item of ``b``."""
    seen = {key(item) for item in b}
    return [item for item in a if key(item) not in seen]
  1. a set of b's keys makes each lookup O(1)
examples✓ 3 doctests · 3.11–3.14
passed on Python 3.11 to 3.14: >>> from math import floorpassed on Python 3.11 to 3.14: >>> difference_by([2.1, 1.2], [2.3, 3.4], floor)[1.2]passed on Python 3.11 to 3.14: >>> difference_by([{"x": 2}, {"x": 1}], [{"x": 1}], lambda d: d["x"])[{'x': 2}]
Edit the function or the examples and run the doctests here, on Python 3.14. Python loads only when you click (about 7 MB, cached after the first time).

How it works

  • The keys of b go into a set, so each lookup is O(1).
  • Items of a keep their order and their duplicates.

Complexity: O(n + m) time, O(m) space

Importfrom pysnippets.lists.difference_by import difference_byNo dependencies: copy difference_by.py into your project, or clone the repo.

Adapted from difference-by in 30-seconds-of-python by the 30 seconds of code contributors, CC BY 4.0. Changed: Typed; fixed the example's invalid result syntax. Suggest an edit.