Python: Map a function over recursive iterables

后端 未结 5 2240
孤独总比滥情好
孤独总比滥情好 2021-02-13 11:42

I have an arbitrarily nested iterable like so:

numbers = (1, 2, (3, (4, 5)), 7)

and I\'d like to map a function over it without changing the st

5条回答
  •  我在风中等你
    2021-02-13 12:16

    Everyone before has mentioned the number of things one might possibly need for any flavour of a flatten function, but there was something that I've been playing with as an exercise in learning the language (so Python noob alert) that I didn't see quite put together here. Basically I wanted for my flatten to be able to handle any Iterables, of any length and nesting in the most efficient (time and space) way possible. This lead me to the generator pattern, and the first requirement I posed for my function was nothing to be created before its time.

    My other requirement was the absence of any explicit looping (for/while) because why not: at least since the helpful addition of yield from in Python 3.3 I was pretty sure it was possible. It would have to be recursive of course, but getting it to give a proper, "flat" generator proved trickier than I thought. So here's my 2p, illustrating the wonderful chain and, I suspect, the kind of situation (a bit more abstracted of course) it was made for:

    from itertools import chain
    from collections import Iterable
    
    def flatten(items):
        if isinstance(items,Iterable):
            yield from chain(*map(flatten,items))    
        else:
            yield items
    
    items = [0xf, [11, 22, [23, (33,(4, 5))], 66, [], [77]], [8,8], 99, {42}]
    print(list(flatten(items)))
    

    Unfortunately for my for-free ambitious project (and ego), according to some pretty rough benchmarking this is ~30% slower than the version using for:

    def flatten(items):
        for item in items:
            if isinstance(item,Iterable):
                yield from flatten(item)
            else:
                yield item
    

    a variant of which was already given by Uriel. I hope it is however a good illustration of the flexibility and power of Python used in a quasi-functional way, especially for others new to the language.

    Edit: to avoid splitting up strings in individual list items, one can append and not isinstance(item,(str,bytes)) to the conditional. And other various bells and whistles that would detract from the point.

提交回复
热议问题