Python
dictionary
closest key
programming
tutorial

Python find closest key in a dictionary from the given input key

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Finding the closest key in a dictionary means locating the key whose value is numerically nearest to a given input. Python has no built-in method for this, but you can use min() with a key function based on abs() to find the closest match in a single pass. For sorted keys, bisect provides O(log n) lookup instead of O(n).

Method 1: min() with abs() (Simple)

python
1data = {10: "a", 20: "b", 35: "c", 50: "d", 80: "e"}
2
3def find_closest_key(d, target):
4    return min(d.keys(), key=lambda k: abs(k - target))
5
6print(find_closest_key(data, 27))  # 20 (distance 7, vs 35 distance 8)
7print(find_closest_key(data, 33))  # 35 (distance 2)
8print(find_closest_key(data, 50))  # 50 (exact match)
9print(find_closest_key(data, 0))   # 10 (closest to 0)

min() iterates over all keys once, computing abs(k - target) for each. Time complexity is O(n).

Method 2: Reusable Function with Edge Cases

python
1def find_closest_key(d, target):
2    if not d:
3        raise ValueError("Dictionary is empty")
4    return min(d.keys(), key=lambda k: abs(k - target))
5
6# Get the value too
7def find_closest_value(d, target):
8    if not d:
9        raise ValueError("Dictionary is empty")
10    closest_key = min(d.keys(), key=lambda k: abs(k - target))
11    return closest_key, d[closest_key]
12
13data = {100: "low", 200: "medium", 500: "high"}
14
15key, value = find_closest_value(data, 180)
16print(f"Closest key: {key}, value: {value}")
17# Closest key: 200, value: medium

Method 3: Using bisect for Sorted Keys (O(log n))

When the dictionary has many keys and you perform repeated lookups, sorting the keys once and using binary search is faster.

python
1import bisect
2
3def find_closest_key_fast(sorted_keys, target):
4    idx = bisect.bisect_left(sorted_keys, target)
5
6    if idx == 0:
7        return sorted_keys[0]
8    if idx == len(sorted_keys):
9        return sorted_keys[-1]
10
11    before = sorted_keys[idx - 1]
12    after = sorted_keys[idx]
13
14    # Return the closer one (prefer lower on tie)
15    if target - before <= after - target:
16        return before
17    return after
18
19data = {10: "a", 20: "b", 35: "c", 50: "d", 80: "e"}
20sorted_keys = sorted(data.keys())  # [10, 20, 35, 50, 80] — sort once
21
22print(find_closest_key_fast(sorted_keys, 27))  # 20
23print(find_closest_key_fast(sorted_keys, 33))  # 35
24print(find_closest_key_fast(sorted_keys, 65))  # 50 (distance 15) vs 80 (distance 15) → 50 (tie: prefer lower)

Sorting is O(n log n) once; each lookup is O(log n). For a single lookup, min() is simpler and equally fast.

Method 4: Finding All Keys Within a Tolerance

Sometimes you want all keys close to the target, not just the closest:

python
1def find_keys_within(d, target, tolerance):
2    return [k for k in d if abs(k - target) <= tolerance]
3
4data = {10: "a", 20: "b", 22: "c", 35: "d", 50: "e"}
5
6print(find_keys_within(data, 21, 2))   # [20, 22]
7print(find_keys_within(data, 30, 10))  # [20, 22, 35]
8print(find_keys_within(data, 100, 5))  # []

Method 5: Float and DateTime Keys

The approach works with any type that supports subtraction and abs():

python
1from datetime import datetime, timedelta
2
3timestamps = {
4    datetime(2025, 1, 1): "New Year",
5    datetime(2025, 3, 15): "Mid March",
6    datetime(2025, 6, 21): "Summer Solstice",
7    datetime(2025, 12, 25): "Christmas",
8}
9
10target = datetime(2025, 3, 10)
11
12# For datetime, abs() does not work directly — use timedelta comparison
13closest = min(timestamps.keys(), key=lambda k: abs((k - target).total_seconds()))
14print(f"{closest.date()}{timestamps[closest]}")
15# 2025-03-15 — Mid March
python
1# Float keys
2measurements = {0.5: "low", 1.2: "medium", 2.8: "high", 4.1: "very high"}
3
4closest = min(measurements.keys(), key=lambda k: abs(k - 1.5))
5print(closest)  # 1.2

Method 6: Using NumPy for Large Datasets

For dictionaries with millions of keys, NumPy vectorized operations are significantly faster:

python
1import numpy as np
2
3data = {i: f"value_{i}" for i in range(0, 1_000_000, 7)}  # 142,857 keys
4
5keys_array = np.array(list(data.keys()))
6target = 500_042
7
8# Vectorized — much faster than Python loop for large data
9idx = np.argmin(np.abs(keys_array - target))
10closest_key = keys_array[idx]
11
12print(closest_key)  # 500_045 (nearest multiple of 7)
13print(data[closest_key])  # value_500045

Handling Ties

When two keys are equidistant from the target, min() returns the first one encountered. Dictionary iteration order is insertion order in Python 3.7+, so the result depends on insertion order:

python
1data = {10: "a", 30: "b"}
2
3# Both 10 and 30 are distance 10 from target 20
4print(min(data.keys(), key=lambda k: abs(k - 20)))  # 10 (first inserted)
5
6# To explicitly prefer lower key on tie:
7def find_closest_prefer_lower(d, target):
8    return min(d.keys(), key=lambda k: (abs(k - target), k))
9
10print(find_closest_prefer_lower(data, 20))  # 10
11
12# To prefer higher key on tie:
13def find_closest_prefer_higher(d, target):
14    return min(d.keys(), key=lambda k: (abs(k - target), -k))
15
16print(find_closest_prefer_higher(data, 20))  # 30

Common Pitfalls

  • Empty dictionary: min() raises ValueError on an empty sequence. Always check if not d before calling min().
  • Non-numeric keys: abs(k - target) only works with numeric types (int, float). For string keys or custom objects, define a distance function appropriate to your domain.
  • Using bisect without sorting: bisect.bisect_left requires a sorted list. Passing an unsorted list produces incorrect results silently — no error is raised.
  • Dictionary ordering assumptions: Do not assume dictionary keys are sorted. Even if you insert keys in order, using min() with a key function is correct regardless of iteration order.
  • Performance with repeated lookups: If you call find_closest_key() many times on the same dictionary, sort the keys once and use bisect for each lookup. The O(n log n) sort cost is amortized across lookups.

Summary

  • Use min(d.keys(), key=lambda k: abs(k - target)) for simple one-off lookups — O(n)
  • Use bisect on sorted keys for repeated lookups — O(log n) per lookup after O(n log n) sort
  • Works with int, float, and datetime keys (use .total_seconds() for datetime)
  • Handle edge cases: empty dictionaries, ties between equidistant keys, non-numeric keys
  • For millions of keys, use NumPy's vectorized argmin for best performance

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.