[Python Wpg] Some beautiful code
Stuart Williams
stuartw at mts.net
Thu Feb 1 22:58:58 EST 2007
Here's a snippet of code we looked at at the last meeting. To
understand it by example see the tests at the bottom.
I made the comment at the meeting that when I rewrote it to be more
general it was much shorter and simpler.
def old_generate_matches(itera, iterb):
"""Take two iterables which return tuples (key, content).
Return pairs of items (as a tuple) that share the key
or an item paired with None if a matching element is missing."""
needed = object() # unique sentinel, so None is allowed in set
a, b = needed, needed
while True:
if a is needed:
try:
keya, a = itera.next()
# if a is None:
# raise ValueError('Iterable cannot contain None')
except StopIteration:
while True:
try:
keyb, b = iterb.next()
yield (None, b)
except StopIteration:
return
if b is needed:
try:
keyb, b = iterb.next()
# if b is None:
# raise ValueError('Iterable cannot contain None')
except StopIteration:
yield (a, None) # we aleady have an A from try above
while True:
try:
keya, a = itera.next()
yield (a, None)
except StopIteration:
return
if keya == keyb:
yield (a, b)
a, b = needed, needed
elif keya > keyb:
yield (None, b)
b = needed
else:
yield (a, None)
a = needed
def generate_matches(*iters):
"""Take N iterables which return tuples (key, content).
Return tuples of items that share the key, filling with
with None if a matching element is missing."""
nelements = len(iters)
needed = object() # a sentinel that's better than None
done = object()
alldone = [done] * nelements
keys = [needed] * nelements
elements = [None] * nelements
while True: # always at least one needed when we enter
for i in range(nelements):
if keys[i] is needed:
try:
keys[i], elements[i] = iters[i].next()
except StopIteration:
keys[i] = done
elements[i] = None
# we now have 3 values, maybe less, maybe all done
if keys == alldone:
break
minkey = min(keys)
results = [None] * nelements
for i in range(nelements):
if keys[i] == minkey:
results[i] = elements[i]
keys[i] = needed
yield results
def gen_gm(a, b):
return (iter([(int(e), int(e)) for e in a.split()]),
iter([(int(e), int(e)) for e in b.split()]))
def test_generate_matches():
assert (list(generate_matches(*gen_gm('1 2 3', '1 2 3')))
== [[1, 1], [2, 2], [3, 3]])
assert (list(generate_matches(*gen_gm('1 2', '1 2 3')))
== [[1, 1], [2, 2], [None, 3]])
assert (list(generate_matches(*gen_gm('1 2 3', '1 2')))
== [[1, 1], [2, 2], [3, None]])
assert (list(generate_matches(*gen_gm('1 2 4 7 8', '1 2 3 5 6 8')))
== [[1, 1], [2, 2], [None, 3], [4, None], [None, 5], [None, 6], [7, None], [8, 8]])
More information about the Winnipeg
mailing list