Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do something to a collection and then return the same type as the collection

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?

like image 974
bitmask Avatar asked Oct 23 '25 03:10

bitmask


1 Answers

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.

like image 131
Azat Ibrakov Avatar answered Oct 25 '25 18:10

Azat Ibrakov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!