Skip to content

Instantly share code, notes, and snippets.

@tokland
Last active December 18, 2015 11:50
Show Gist options
  • Save tokland/e112ebaefbe65f0d638f to your computer and use it in GitHub Desktop.
Save tokland/e112ebaefbe65f0d638f to your computer and use it in GitHub Desktop.
Pure functional implementation of D'Hondt method
# Pure functional implementation of D'Hondt method
from itertools import islice, count
from collections import Counter
from heapq import merge
def percentage(numerator, denominator):
return 100.0 * numerator / denominator
def take(n, it):
return islice(it, n)
def get_party_fractions(votes, name):
party_fractions = (float(votes) / n for n in count(1))
return ((-fraction, name) for fraction in party_fractions)
def get_fractions(results):
sorted_results = sorted(((votes, name) for (name, votes) in results.items()), reverse=True)
return (get_party_fractions(votes, name) for (votes, name) in sorted_results)
def get_results_over_threshold(results, min_percentage):
total_votes = sum(results.values())
return dict((name, votes) for (name, votes) in results.items()
if percentage(votes, total_votes) >= min_percentage)
def dhondt(results, total_seats, min_percentage=0):
"""
Return the seats distribution of results votes following the D'Hondt method.
>>> dhondt({"A": 10, "B": 8, "C": 3, "D": 2}, 8)
Counter({'A': 4, 'B': 3, 'C': 1})
>>> dhondt({"A": 6, "B": 3, "C": 2}, 8, min_percentage=20)
Counter({'A': 6, 'B': 2})
"""
results_over_threshold = get_results_over_threshold(results, min_percentage)
fractions = get_fractions(results_over_threshold)
assigned_party_names = (name for (fraction, name) in merge(*fractions))
return Counter(take(total_seats, assigned_party_names))
if __name__ == "__main__":
import doctest
doctest.testmod()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment