bpo-4356: Add key function support to the bisect module by rhettinger · Pull Request #20556 · python/cpython (original) (raw)
I think the API is correct in that it supports typical usage patterns. insort() will insert entire records and bisect() will scan the key field for the first match in a range at or above the key value.
CREATE INDEX age_ndx INDEX ON People (age);
INSERT INTO People Values ("raymond", 50);
/* Find the youngest person at or over 42 */
SELECT name, age FROM People WHERE age >= 42 ORDER BY age LIMIT 1;
from bisect import bisect, insort
from operator import attrgetter
from collections import namedtuple
from pprint import pp
Person = namedtuple('Person', ('name', 'age'))
people = [
Person('tom', 30),
Person('sue', 40),
Person('mark', 35),
Person('peter', 55),
]
people.sort(key=attrgetter('age'))
new_person = Person('randy', 50)
insort(people, new_person, key=attrgetter('age'))
pp(people)
print(people[bisect(people, 42, key=attrgetter('age'))])
If bisect() required an entire record as an input, it would preclude the ability to do searches like like this.
# https://www.quickenloans.com/blog/federal-income-tax-brackets
Bracket = namedtuple('Bracket', ('rate', 'single', 'married_joint', 'married_sep', 'head'))
brackets_2019 = [
Bracket(0.10, 9_700, 19_400, 9_700, 13_850),
Bracket(0.12, 39_475, 78_950, 39_475, 52_850),
Bracket(0.22, 84_200, 168_400, 84_200, 84_200),
Bracket(0.24, 160_725, 321_450, 160_725, 160_700),
]
taxable_income = 60_000
for status in ('single', 'married_joint', 'married_sep', 'head'):
i = bisect(brackets_2019, taxable_income, key=attrgetter(status))
bracket = brackets_2019[i]
print(status, bracket.rate)