forked from jefk/billfriar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
friar.py
executable file
·101 lines (80 loc) · 2.7 KB
/
friar.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#! /usr/bin/python3.2
import sys
import re
import heapq
from collections import Counter
class MaxHeap():
''' making heapq classy
'''
def __init__(self, ls = []):
''' ls is a list of tuples in this format
[ (val, label), (val, label), ... ]
'''
# multiply val by -1 to make this into a max heap, heapq is min heap
self.heap = [ [-1 * val, label] for val, label in ls ]
heapq.heapify(self.heap)
def pop(self):
entry = heapq.heappop(self.heap)
entry[0] = -1 * entry[0]
return entry
def push(self, entry):
heapq.heappush(self.heap, [-1 * entry[0], entry[1] ])
def is_empty(self):
return len(self.heap) == 0
def __str__(self):
return self.heap.__str__()
def parse(line):
''' lines are expect to be in this form
[debtor] owes [lender] [dollars]
'''
line = line.strip()
line = re.sub('\s+', ' ', line)
debtor, rest = line.split(' owes ', 1)
lender, rest = rest.split(' ', 1)
if ' ' in rest.strip():
amount, memo = rest.split(' ', 1)
else:
amount = rest
memo = ''
amount = amount.replace('$', '')
amount = float(amount)
return debtor.lower(), lender.lower(), amount, memo
def make_heaps(credit):
debtor_values = [ (-1 * credit[person], person) for person in credit if credit[person] < 0 ]
lender_values = [ (credit[person], person) for person in credit if credit[person] > 0 ]
return MaxHeap(debtor_values), MaxHeap(lender_values)
def shuffle(credit):
'''
'''
transactions = []
debtors, lenders = make_heaps(credit)
while not debtors.is_empty() and not lenders.is_empty():
debtor = debtors.pop()
lender = lenders.pop()
debtor[0] = round(debtor[0], 2)
lender[0] = round(lender[0], 2)
amount = min(debtor[0], lender[0])
if debtor[0] > lender[0]:
debtor[0] -= amount
debtors.push(debtor)
elif debtor[0] < lender[0]:
lender[0] -= amount
lenders.push(lender)
else:
# the debts are equal, so neither goes back on the heap
pass
transactions.append( {'payer':debtor[1], 'payee':lender[1], 'amount':amount} )
return transactions
if __name__ == "__main__":
credit = Counter()
for line in sys.stdin:
try:
debtor, lender, amount, memo = parse(line)
except:
continue
print( '{debtor} owes {lender} ${amount} {memo}'.format( **locals() ) )
credit[lender] += amount
credit[debtor] -= amount
print()
for transaction in shuffle(credit):
print('{payer} pays {payee} ${amount}'.format(**transaction) )