3

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?

1

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

You need to just iterate over one dict f, and in the comprehension, replace the value of f with the value of g

f = {0:'a', 1:'b'}
g = {'a':'apple', 'b': 'banana'}
new_dict = {k: g[v] for k, v in f.items()}
# Value of new_dict = {0: 'apple', 1: 'banana'}

Comments

0

The correct dict comprehension would be:

{i:g[f[i]] for i in f}

You did:

{i:g[j] for i in f for j in g}

That mapped every i to every i to every value in g, but then dict removed duplicate keys.

To see what is going on, try generating a list instead:

>>> [(i, g[j]) for i in f for j in g]
[(0, 'apple'), (0, 'banana'), (1, 'apple'), (1, 'banana')]

In the correct case:

>>> [(i, g[f[i]]) for i in f]
[(0, 'apple'), (1, 'banana')]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.