Skip to content

Instantly share code, notes, and snippets.

@dorianturba
Last active April 20, 2023 17:47
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save dorianturba/e9c4210a5545d8447ecd35dad8a43355 to your computer and use it in GitHub Desktop.
Save dorianturba/e9c4210a5545d8447ecd35dad8a43355 to your computer and use it in GitHub Desktop.
Count how many people are alive per year, based on their birthyear and deathyear, aims for performances.
import collections
import random
import timeit
pop = [
(b := random.randint(1900, 2000), random.randint(b + 1, b + 100))
for _ in range(10000)
]
# 0.162 s (with 10000 people [1,100] years old)
def count_living_per_year(population: list[tuple[int, int]]) -> dict[int, int]:
living_per_year = {}
for birth, death in population:
if birth in living_per_year:
living_per_year[birth] += 1
else:
living_per_year[birth] = 1
if death in living_per_year:
living_per_year[death] -= 1
else:
living_per_year[death] = -1
for year in range(min(living_per_year), max(living_per_year)):
living_per_year[year] += living_per_year.get(year - 1, 0)
living_per_year.pop(max(living_per_year))
return living_per_year
print(sorted(tuple(count_living_per_year(pop).items())))
print(
timeit.timeit(
"count_living_per_year(pop)",
globals=globals(),
number=100,
)
)
# 0.118 s (with 10000 people [1,100] years old)
def count_living_per_year(population: list[tuple[int, int]]) -> dict[int, int]:
living_per_year = collections.defaultdict(int)
for birth, death in population:
living_per_year[birth] += 1
living_per_year[death] -= 1
min_, max_ = min(living_per_year), max(living_per_year)
for year in range(min_, max_):
living_per_year[year] += living_per_year[year - 1]
del living_per_year[min_ - 1], living_per_year[max_]
return living_per_year
print(sorted(tuple(count_living_per_year(pop).items())))
print(
timeit.timeit(
"count_living_per_year(pop)",
globals=globals(),
number=100,
)
)
# 0.105 s (with 10000 people [1,100] years old)
def count_living_per_year(population: list[tuple[int, int]]) -> dict[int, int]:
births = collections.Counter(birth for birth, _ in population)
deaths = collections.Counter(death for _, death in population)
living_per_year = births
for year in range(min(births), max(deaths)):
living_per_year[year] += living_per_year[year - 1] - deaths[year]
return living_per_year
print(sorted(tuple(count_living_per_year(pop).items())))
print(
timeit.timeit(
"count_living_per_year(pop)",
globals=globals(),
number=100,
)
)
# 0.108 s (with 10000 people [1,100] years old)
def count_living_per_year(population: list[tuple[int, int]]) -> dict[int, int]:
births = collections.Counter(birth for birth, _ in population)
deaths = collections.Counter(death for _, death in population)
(delta_per_year := births).subtract(deaths)
living_per_year = collections.Counter()
for year in range(min(delta_per_year), max(delta_per_year)):
living_per_year[year] = living_per_year[year - 1] + delta_per_year[year]
return living_per_year
print(sorted(tuple(count_living_per_year(pop).items())))
print(
timeit.timeit(
"count_living_per_year(pop)",
globals=globals(),
number=100,
)
)
# 0.093 s (with 10000 people [1,100] years old)
def count_living_per_year(population: list[tuple[int, int]]) -> dict[int, int]:
births, deaths = zip(*population)
births_counter = collections.Counter(births)
deaths_counter = collections.Counter(deaths)
living_per_year = collections.Counter()
for year in range(min(births_counter), max(deaths_counter)):
delta_living = births_counter[year] - deaths_counter[year]
living_per_year[year] = living_per_year[year - 1] + delta_living
return living_per_year
print(sorted(tuple(count_living_per_year(pop).items())))
print(
timeit.timeit(
"count_living_per_year(pop)",
globals=globals(),
number=100,
)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment