Help me write idiomatically correct Python
Monday, September 29th, 2008Why can’t the features I like from every programming language be available all the time? It really bugs me that, for instance, I can’t get lazy lists and patter matching in Python and I can’t get, well, there’s got to be something that Python has that’s sort of a pain in Haskell. I/O, for example.
Anyway, I want code that does this:
import Prelude hiding (Left, Right)
data EitherBoth a = Left a | Right a | Both a a deriving Show
cmpseq :: (Ord a) => (a -> a -> Ordering) -> [a] -> [a] -> [EitherBoth a]
cmpseq _ [] rs = map Right rs
cmpseq _ ls [] = map Left ls
cmpseq cmp (l:ls) (r:rs) = case (cmp l r) of
LT -> Left l : cmpseq cmp ls (r:rs)
GT -> Right r : cmpseq cmp (l:ls) rs
EQ -> Both l r : cmpseq cmp ls rs
So given two ordered lists and a comparison function, I want to know (efficiently, and preserving order) which elements are just in one list and which are in both. The Haskell version is pretty clear and pretty concise. (Bonus points: if you have a better way to do this in Haskell — and I’m sure there is one — I’d love to hear about it.)
So far, the best I can do in Python is this rather ugly mess:
def cmpseq(f, xs, ys):
nx, ny = len(xs), len(ys)
ix, iy = 0, 0
while ix < nx and iy < ny:
r = f(xs[ix], ys[iy])
if -1 == r:
yield (xs[ix], None)
ix = 1 + ix
elif 1 == r:
yield (None, ys[iy])
iy = 1 + iy
else:
yield (xs[ix], ys[iy])
ix, iy = 1 + ix, 1 + iy
while ix < nx:
yield (xs[ix], None)
ix = 1 + ix
while iy < ny:
yield (None, ys[iy])
iy = 1 + iy
Yuck. I’m going to go out on a limb and say that five yields is too many. What’s the idiomatically correct way to do this? Perhaps something to do with feeding values back in to generators? Python language lawyers: please show me the error of my ways!






