I want to apply a function f to a collection xs but keep its type. If I use map, I get a 'map object':
def apply1(xs, f):
return map(f, xs)
If I know that xs is something like a list or tuple I can force it to have the same type:
def apply2(xs, f):
return type(xs)(map(f, xs))
However, that quickly breaks down for namedtuple (which I am currently in a habbit of using) -- because to my knowledge namedtuple needs to be constructed with unpack syntax or by calling its _make function. Also, namedtuple is const, so I cannot iterate over all entries and just change them.
Further problems arise from use of a dict.
Is there a generic way to express such an apply function that works for everything that is iterable?
Looks like a perfect task for functools.singledispatch decorator:
from functools import singledispatch
@singledispatch
def apply(xs, f):
return map(f, xs)
@apply.register(list)
def apply_to_list(xs, f):
return type(xs)(map(f, xs))
@apply.register(tuple)
def apply_to_tuple(xs, f):
try:
# handle `namedtuple` case
constructor = xs._make
except AttributeError:
constructor = type(xs)
return constructor(map(f, xs))
after that apply function can be simply used like
>>> apply([1, 2], lambda x: x + 1)
[2, 3]
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(10, 5)
>>> apply(p, lambda x: x ** 2)
Point(x=100, y=25)
I'm not aware of what is desired behavior for dict objects though, but the greatness of this approach that it is easy to extend.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With