map/filter/reduce/lambda opinions and background unscientific mini-survey
Tom Anderson
twic at urchin.earth.li
Tue Jul 5 09:20:10 EDT 2005
On Mon, 4 Jul 2005, Ron Adam wrote:
> George Sakkis wrote:
>
>> And finally for recursive flattening:
>>
>> def flatten(seq):
>> return reduce(_accum, seq, [])
>>
>> def _accum(seq, x):
>> if isinstance(x,list):
>> seq.extend(flatten(x))
>> else:
>> seq.append(x)
>> return seq
>>
>>
>>>>> flatten(seq)
>>
>> [1, 2, 3, 4, 5, 6]
>
> How about this for a non recursive flatten.
>
> def flatten(seq):
> s = []
> while seq:
> while isinstance(seq[0],list):
> seq = seq[0]+seq[1:]
> s.append(seq.pop(0))
> return s
>
> seq = [[1,2],[3],[],[4,[5,6]]]
> flatten(seq)
The trouble with these is that they make a lot of temporary lists -
George's version does it with the recursive calls to flatten, and Ron's
with the slicing and concatenating. How about a version which never makes
new lists, only appends the base list? We can use recursion to root
through the lists ...
def isiterable(x):
return hasattr(x, "__iter__") # close enough for government work
def visit(fn, x): # perhaps better called applytoall
if (isiterable(x)):
for y in x: visit(fn, y)
else:
fn(x)
def flatten(seq):
a = []
def appendtoa(x):
a.append(x)
visit(appendtoa, seq)
return a
If you hate recursion, you can write a non-recursive version of visit;
you'll have to manage a stack of lists yourself, though. Something like:
def visit(fn, x):
if (not isiterable(x)): x = (x,)
stack = [None] # stack of iterators
cur = iter(x) # current iterator
while (cur != None):
try:
thing = cur.next()
if (isiterable(thing)):
stack.append(cur)
cur = iter(thing)
else:
fn(thing)
except StopIteration:
cur = stack.pop()
There might be a cleverer way to do this.
tom
--
The revolution will not be televised. The revolution will be live.
More information about the Python-list
mailing list