Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stuck defining composition function in python

input: two functions f and g, represented as dictionaries, such that g ◦ f exists. output: dictionary that represents the function g ◦ f. example: given f = {0:’a’, 1:’b’} and g = {’a’:’apple’, ’b’:’banana’}, return {0:’apple’, 1:’banana’}.

The closest to the correct answer I have is with {i:g[j] for i in f for j in g} which outputs {0: 'apple', 1: 'apple'}. What am I doing wrong?

like image 972
blionzion Avatar asked Jul 24 '26 11:07

blionzion


1 Answers

Other answers are great, but they create an entire dictionary which may be slow. If you only want a read-only composition, then the following class will solve your problems:

class Composition_mapping(collections.abc.Mapping):
    
    def __init__(self, f, g):
        self.f = f
        self.g = g
    
    def __iter__(self):
        return iter(self.g)
    
    def __len__(self):
        return len(self.g)
        
    def keys(self):
        return self.g.keys()
    
    def __getitem__(self, item):
        return self.f[self.g[item]]

For example:

a = {1: 5}

b = {5:9, 7 : 8}

c = Composition_mapping(b,a)

print(c[1])

>>> 9

If you decide to make it a dict, you can always do:

c = dict(c)
print(c)
>>> {1: 9}

This is safe, because Composition_mapping satisfies the mapping protocol, which means it is considered as a mapping. A mapping is an interface (protocol) for read-only dictionary-like structures. Note that it is not necessary to inherit from collections.abc.Mapping, you just need to implement the methods __getitem__, __iter__, __len__ __contains__, keys, items, values, get, __eq__, and __ne__ to be a mapping; after all Python favors duck typing. The reason my code inherits from collections.abc.Mapping is that it implements all the other methods for you except __getitem__, __iter__, __len__. See the official documentation for the details about protocols.

Creating a composition with this method will have constant time cost no matter how big the composed functions are. The look-ups can be a little bit slower due to double look-ups and extra function call, but you can always use c = dict(c) if you are going to make lots of calls in a performance critical part. More importantly, if you change a and b anywhere in your code, the changes will be reflected on c.

like image 57
Fırat Kıyak Avatar answered Jul 26 '26 03:07

Fırat Kıyak



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!