On 6/6/2011 9:42 AM, jyoun...@kc.rr.com wrote:
f = lambda x, n, acc=[]: f(x[n:], n, acc+[(x[:n])]) if x else acc
Packing tail recursion into one line is bad for both understanding and
refactoring. Use better names and a docstring gives
def group(seq, n):
'Yield from seq successive disjoint slices of length n plus the
remainder'
for i in range(0,len(seq), n):
yield seq[i:i+n]
[I added back the last 'n' that got deleted somehow]
Thank you all very much for this incredible help! The original code
now makes sense, and I was thrilled to see better and more efficient
ways of doing this. Thanks for taking the time to share your
thoughts as well as the excellent detail everyone shared… I really
appreciate it!
You are welcome.
Let me add something not said much here about designing functions: start
with both a clear and succinct definition *and* test cases. (I only
started writing tests first a year ago or so.) Test cases help test the
definition statement as well as the yet-to-be-written code. They also
make re-factoring much safer. I think test cases should start with null
inputs. For this function:
for inn,out in (
(('',1), []), # no input, no output
(('abc',0), []), # definition unclear, could be error
(('abc',1), ['a','b','c']),
(('abcd',2), ['ab','cd']),
(('abcde',2), ['ab', 'cd', 'e']), # could change this
):
assert list(group(*inn)) == out, (inn,out)
This fails with
ValueError: range() arg 3 must not be zero
I will let you think about and try out what the original code 'f=../
does with n=0. It is not good. A third problem with lambda expressions
is no test for bad inputs. They were added to Python for situations
where one needs a function as an argument and and the return expression
is self-explanatory, clearly correct, and safe for any inputs it could
get in the context it is passed into. For example, lambda x: 2*x.
This works:
def group(seq, n):
'Yield from seq successive disjoint slices of length n & the remainder'
if n<=0: raise ValueError('group size must be positive')
for i in range(0,len(seq), n):
yield seq[i:i+n]
for inn,out in (
(('',1), []), # no input, no output
#(('abc',0), ValueError), # group size positive
(('abc',1), ['a','b','c']),
(('abcd',2), ['ab','cd']),
(('abcde',2), ['ab', 'cd', 'e']), # could change this
):
assert list(group(*inn)) == out, (inn,out)
I have written a function test function that I will post or upload to
PyPI sometime. It accepts i/o pairs with error 'outputs', like the one
commented out above.
--
Terry Jan Reedy
--
http://mail.python.org/mailman/listinfo/python-list