# Fun with linked-lists. (2.00)
class Pair:
def __init__(self, first=None, rest=None):
self.first = first
self.rest = rest
def __repr__(self):
return '(' + ' '.join(map(str, ltoa(self))) + ')'
def atol(a):
# Array to linked-list.
r = None
for x in reversed(a):
r = Pair(x, r)
return r
def ltoa(l):
# Linked-list to array.
return foldl(lambda init, x: init + [x], [], l)
def _append(tail, l):
assert l is None or isinstance(l, Pair), 'Pair expected!'
# Internal: Copy and append elements.
while l:
tail.rest = Pair(l.first)
tail = tail.rest
l = l.rest
return tail
def appendl(ls):
# Append all lists.
temp = Pair()
foldl(lambda init, x: _append(init, x), temp, ls)
return temp.rest
def reversel(l):
# Reverse a list.
return foldl(lambda init, x: Pair(x, init), None, l)
def foldl(proc, init, l):
# Build result by applying a procedure to list elements.
return foldlp(lambda init, p: proc(init, p.first), init, l)
def foldlp(proc, init, l):
# Build result by applying a procedure to list pairs.
while l:
init = proc(init, l)
l = l.rest
return init
def foldrightl(proc, init, l):
# Build result by applying a procedure to list elements last to first.
return foldrightlp(lambda init, p: proc(init, p.first), init, l)
def foldrightlp(proc, init, l):
# Build result by applying a procedure to list pairs last to first.
# (Prototypical implementation; limited by maximum recursion depth)
if not l:
return init
return proc(foldrightlp(proc, init, l.rest), l)
def foldrightlp(proc, init, l):
# Build result by applying a procedure to list pairs last to first.
# (Continuation passing style and trampoline eliminates recursion)
def cps_detail(l, k):
if not l:
return k(init)
return lambda: cps_detail(l.rest, lambda x: lambda: k(proc(x, l)))
def trampoline(t):
while callable(t):
t = t()
return t
return trampoline(cps_detail(l, lambda x: x))
def mapl(proc, l):
# Map procedure over list elements; return list of results.
return maplp(lambda p: proc(p.first), l)
def maplp(proc, l):
# Map procedure over list pairs; return list of results.
# (Fold is more efficient than foldright but ...)
return reversel(foldlp(lambda init, p: Pair(proc(p), init), None, l))
def maplp(proc, l):
# Map procedure over list pairs; return list of results.
# (... I want to test foldright)
return foldrightlp(lambda init, p: Pair(proc(p), init), None, l)
def appendmapl(proc, l):
# Map procedure over list elements; return appended results.
return appendmaplp(lambda p: proc(p.first), l)
def appendmaplp(proc, l):
# Map procedure over list pairs; return appended results.
return appendl(maplp(proc, l))
def combinationsl(l, k):
# Generate combinations from list.
if k == 0:
return Pair()
return appendmaplp(lambda r: mapl(lambda c: Pair(r.first, c),
combinationsl(r.rest, k-1)), l)
# Main.
n = 5
l1 = atol(list(range(n)))
l2 = atol(list(range(n, n*2)))
l3 = atol(list(range(n*2, n*3)))
print(l1)
print(ltoa(l1))
print(reversel(l1))
print(mapl(lambda x: x**2, l1))
print(appendl(atol([None, l1, None, None, l2, None, None, l3, None])))
print(appendmapl(lambda x: Pair(x), l1))
for k in range(n+1):
print(f'{n} choose {k}')
print(combinationsl(l1, k))
# Time.
from time import process_time
def _timeit(thunk):
t = process_time()
thunk()
print('Elapsed: {:.6f}s'.format(process_time() - t))
def make_f(n, k, count):
l = atol(list(range(n)))
def f():
for _ in range(count):
combinationsl(l, k)
return f
_timeit(make_f(8, 4, 400))
_timeit(make_f(16, 8, 1))
IyBGdW4gd2l0aCBsaW5rZWQtbGlzdHMuICgyLjAwKQoKY2xhc3MgUGFpcjoKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBmaXJzdD1Ob25lLCByZXN0PU5vbmUpOgogICAgICAgIHNlbGYuZmlyc3QgPSBmaXJzdAogICAgICAgIHNlbGYucmVzdCA9IHJlc3QKCiAgICBkZWYgX19yZXByX18oc2VsZik6CiAgICAgICAgcmV0dXJuICcoJyArICcgJy5qb2luKG1hcChzdHIsIGx0b2Eoc2VsZikpKSArICcpJwoKZGVmIGF0b2woYSk6CiAgICAjIEFycmF5IHRvIGxpbmtlZC1saXN0LgogICAgciA9IE5vbmUKICAgIGZvciB4IGluIHJldmVyc2VkKGEpOgogICAgICAgIHIgPSBQYWlyKHgsIHIpCiAgICByZXR1cm4gcgoKZGVmIGx0b2EobCk6CiAgICAjIExpbmtlZC1saXN0IHRvIGFycmF5LgogICAgcmV0dXJuIGZvbGRsKGxhbWJkYSBpbml0LCB4OiBpbml0ICsgW3hdLCBbXSwgbCkKCmRlZiBfYXBwZW5kKHRhaWwsIGwpOgogICAgYXNzZXJ0IGwgaXMgTm9uZSBvciBpc2luc3RhbmNlKGwsIFBhaXIpLCAnUGFpciBleHBlY3RlZCEnCiAgICAjIEludGVybmFsOiBDb3B5IGFuZCBhcHBlbmQgZWxlbWVudHMuCiAgICB3aGlsZSBsOgogICAgICAgIHRhaWwucmVzdCA9IFBhaXIobC5maXJzdCkKICAgICAgICB0YWlsID0gdGFpbC5yZXN0CiAgICAgICAgbCA9IGwucmVzdAogICAgcmV0dXJuIHRhaWwKCmRlZiBhcHBlbmRsKGxzKToKICAgICMgQXBwZW5kIGFsbCBsaXN0cy4KICAgIHRlbXAgPSBQYWlyKCkKICAgIGZvbGRsKGxhbWJkYSBpbml0LCB4OiBfYXBwZW5kKGluaXQsIHgpLCB0ZW1wLCBscykKICAgIHJldHVybiB0ZW1wLnJlc3QKCmRlZiByZXZlcnNlbChsKToKICAgICMgUmV2ZXJzZSBhIGxpc3QuCiAgICByZXR1cm4gZm9sZGwobGFtYmRhIGluaXQsIHg6IFBhaXIoeCwgaW5pdCksIE5vbmUsIGwpCgpkZWYgZm9sZGwocHJvYywgaW5pdCwgbCk6CiAgICAjIEJ1aWxkIHJlc3VsdCBieSBhcHBseWluZyBhIHByb2NlZHVyZSB0byBsaXN0IGVsZW1lbnRzLgogICAgcmV0dXJuIGZvbGRscChsYW1iZGEgaW5pdCwgcDogcHJvYyhpbml0LCBwLmZpcnN0KSwgaW5pdCwgbCkKCmRlZiBmb2xkbHAocHJvYywgaW5pdCwgbCk6CiAgICAjIEJ1aWxkIHJlc3VsdCBieSBhcHBseWluZyBhIHByb2NlZHVyZSB0byBsaXN0IHBhaXJzLgogICAgd2hpbGUgbDoKICAgICAgICBpbml0ID0gcHJvYyhpbml0LCBsKQogICAgICAgIGwgPSBsLnJlc3QKICAgIHJldHVybiBpbml0CgpkZWYgZm9sZHJpZ2h0bChwcm9jLCBpbml0LCBsKToKICAgICMgQnVpbGQgcmVzdWx0IGJ5IGFwcGx5aW5nIGEgcHJvY2VkdXJlIHRvIGxpc3QgZWxlbWVudHMgbGFzdCB0byBmaXJzdC4KICAgIHJldHVybiBmb2xkcmlnaHRscChsYW1iZGEgaW5pdCwgcDogcHJvYyhpbml0LCBwLmZpcnN0KSwgaW5pdCwgbCkKCmRlZiBmb2xkcmlnaHRscChwcm9jLCBpbml0LCBsKToKICAgICMgQnVpbGQgcmVzdWx0IGJ5IGFwcGx5aW5nIGEgcHJvY2VkdXJlIHRvIGxpc3QgcGFpcnMgbGFzdCB0byBmaXJzdC4KICAgICMgKFByb3RvdHlwaWNhbCBpbXBsZW1lbnRhdGlvbjsgbGltaXRlZCBieSBtYXhpbXVtIHJlY3Vyc2lvbiBkZXB0aCkKICAgIGlmIG5vdCBsOgogICAgICAgIHJldHVybiBpbml0CiAgICByZXR1cm4gcHJvYyhmb2xkcmlnaHRscChwcm9jLCBpbml0LCBsLnJlc3QpLCBsKQoKZGVmIGZvbGRyaWdodGxwKHByb2MsIGluaXQsIGwpOgogICAgIyBCdWlsZCByZXN1bHQgYnkgYXBwbHlpbmcgYSBwcm9jZWR1cmUgdG8gbGlzdCBwYWlycyBsYXN0IHRvIGZpcnN0LgogICAgIyAoQ29udGludWF0aW9uIHBhc3Npbmcgc3R5bGUgYW5kIHRyYW1wb2xpbmUgZWxpbWluYXRlcyByZWN1cnNpb24pCiAgICBkZWYgY3BzX2RldGFpbChsLCBrKToKICAgICAgICBpZiBub3QgbDoKICAgICAgICAgICAgcmV0dXJuIGsoaW5pdCkKICAgICAgICByZXR1cm4gbGFtYmRhOiBjcHNfZGV0YWlsKGwucmVzdCwgbGFtYmRhIHg6IGxhbWJkYTogayhwcm9jKHgsIGwpKSkKICAgIGRlZiB0cmFtcG9saW5lKHQpOgogICAgICAgIHdoaWxlIGNhbGxhYmxlKHQpOgogICAgICAgICAgICB0ID0gdCgpCiAgICAgICAgcmV0dXJuIHQKICAgIHJldHVybiB0cmFtcG9saW5lKGNwc19kZXRhaWwobCwgbGFtYmRhIHg6IHgpKQoKZGVmIG1hcGwocHJvYywgbCk6CiAgICAjIE1hcCBwcm9jZWR1cmUgb3ZlciBsaXN0IGVsZW1lbnRzOyByZXR1cm4gbGlzdCBvZiByZXN1bHRzLgogICAgcmV0dXJuIG1hcGxwKGxhbWJkYSBwOiBwcm9jKHAuZmlyc3QpLCBsKQoKZGVmIG1hcGxwKHByb2MsIGwpOgogICAgIyBNYXAgcHJvY2VkdXJlIG92ZXIgbGlzdCBwYWlyczsgcmV0dXJuIGxpc3Qgb2YgcmVzdWx0cy4KICAgICMgKEZvbGQgaXMgbW9yZSBlZmZpY2llbnQgdGhhbiBmb2xkcmlnaHQgYnV0IC4uLikKICAgIHJldHVybiByZXZlcnNlbChmb2xkbHAobGFtYmRhIGluaXQsIHA6IFBhaXIocHJvYyhwKSwgaW5pdCksIE5vbmUsIGwpKQoKZGVmIG1hcGxwKHByb2MsIGwpOgogICAgIyBNYXAgcHJvY2VkdXJlIG92ZXIgbGlzdCBwYWlyczsgcmV0dXJuIGxpc3Qgb2YgcmVzdWx0cy4KICAgICMgKC4uLiBJIHdhbnQgdG8gdGVzdCBmb2xkcmlnaHQpCiAgICByZXR1cm4gZm9sZHJpZ2h0bHAobGFtYmRhIGluaXQsIHA6IFBhaXIocHJvYyhwKSwgaW5pdCksIE5vbmUsIGwpCgpkZWYgYXBwZW5kbWFwbChwcm9jLCBsKToKICAgICMgTWFwIHByb2NlZHVyZSBvdmVyIGxpc3QgZWxlbWVudHM7IHJldHVybiBhcHBlbmRlZCByZXN1bHRzLgogICAgcmV0dXJuIGFwcGVuZG1hcGxwKGxhbWJkYSBwOiBwcm9jKHAuZmlyc3QpLCBsKQoKZGVmIGFwcGVuZG1hcGxwKHByb2MsIGwpOgogICAgIyBNYXAgcHJvY2VkdXJlIG92ZXIgbGlzdCBwYWlyczsgcmV0dXJuIGFwcGVuZGVkIHJlc3VsdHMuCiAgICByZXR1cm4gYXBwZW5kbChtYXBscChwcm9jLCBsKSkKCmRlZiBjb21iaW5hdGlvbnNsKGwsIGspOgogICAgIyBHZW5lcmF0ZSBjb21iaW5hdGlvbnMgZnJvbSBsaXN0LgogICAgaWYgayA9PSAwOgogICAgICAgIHJldHVybiBQYWlyKCkKICAgIHJldHVybiBhcHBlbmRtYXBscChsYW1iZGEgcjogbWFwbChsYW1iZGEgYzogUGFpcihyLmZpcnN0LCBjKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21iaW5hdGlvbnNsKHIucmVzdCwgay0xKSksIGwpCgojIE1haW4uCgpuID0gNQpsMSA9IGF0b2wobGlzdChyYW5nZShuKSkpCmwyID0gYXRvbChsaXN0KHJhbmdlKG4sIG4qMikpKQpsMyA9IGF0b2wobGlzdChyYW5nZShuKjIsIG4qMykpKQoKcHJpbnQobDEpCnByaW50KGx0b2EobDEpKQpwcmludChyZXZlcnNlbChsMSkpCnByaW50KG1hcGwobGFtYmRhIHg6IHgqKjIsIGwxKSkKcHJpbnQoYXBwZW5kbChhdG9sKFtOb25lLCBsMSwgTm9uZSwgTm9uZSwgbDIsIE5vbmUsIE5vbmUsIGwzLCBOb25lXSkpKQpwcmludChhcHBlbmRtYXBsKGxhbWJkYSB4OiBQYWlyKHgpLCBsMSkpCgpmb3IgayBpbiByYW5nZShuKzEpOgogICAgcHJpbnQoZid7bn0gY2hvb3NlIHtrfScpCiAgICBwcmludChjb21iaW5hdGlvbnNsKGwxLCBrKSkKCiMgVGltZS4KCmZyb20gdGltZSBpbXBvcnQgcHJvY2Vzc190aW1lCgpkZWYgX3RpbWVpdCh0aHVuayk6CiAgICB0ID0gcHJvY2Vzc190aW1lKCkKICAgIHRodW5rKCkKICAgIHByaW50KCdFbGFwc2VkOiB7Oi42Zn1zJy5mb3JtYXQocHJvY2Vzc190aW1lKCkgLSB0KSkKCmRlZiBtYWtlX2YobiwgaywgY291bnQpOgogICAgbCA9IGF0b2wobGlzdChyYW5nZShuKSkpCiAgICBkZWYgZigpOgogICAgICAgIGZvciBfIGluIHJhbmdlKGNvdW50KToKICAgICAgICAgICAgY29tYmluYXRpb25zbChsLCBrKQogICAgcmV0dXJuIGYKCl90aW1laXQobWFrZV9mKDgsIDQsIDQwMCkpCl90aW1laXQobWFrZV9mKDE2LCA4LCAxKSk=