Home > front end >  Composition Function
Composition Function

Time:10-13

I need help with a function that outputs a dictionary that contains the composition between R1 and R2 it's output represents R2 ◦ R1

as of now, I have

def composition(R1,R2):
  d = {i:R2[R1[i]] for i in R1}
  print(d)

this function works inputting

R1 = {1:'a',2:'b',3:'c'}
R2 = {'a':'A','b':'B','c':'C'}
output: {1: 'A', 2: 'B', 3: 'C'}

what I need to work is

R1 = {1 : [2, 3], 2 : [3], 3 : [4], 4 : [1, 3]}
R2 = {1 : [3], 2 : [1, 4], 3 : [2], 4 : [1, 2]}
output should be: R2 ◦ R1 = {1 : [1, 2, 4], 2 : [2], 3 : [1, 2], 4 : [2, 3]}

what I get is unhashable type list

Any help would be great, Thank You.

CodePudding user response:

Since both the values of R1 and R2 are lists, you need nested comprehensions to get all the mapped elements in a flattened result for each key:

R1 = {1 : [2, 3], 2 : [3], 3 : [4], 4 : [1, 3]}
R2 = {1 : [3], 2 : [1, 4], 3 : [2], 4 : [1, 2]}


output = {k1:[n2 for n1 in v1 for n2 in R2[n1]] for k1,v1 in R1.items()}

print(output)
{1: [1, 4, 2], 2: [2], 3: [1, 2], 4: [3, 2]}

CodePudding user response:

Here is a generic solution working in both cases.

In summary, check if the value is a non-string iterable and compose all elements, else just compose the value.

from collections.abc import Iterable
from itertools import chain

def composition(R1, R2):
    return {k1: list(chain(*[R2[e] for e in v1]))
            if isinstance(v1, Iterable)
            and not isinstance(v1, str)
            else v1
            for k1,v1 in R1.items()}

Example 1:

>>> R1 = {1:'a',2:'b',3:'c'}
>>> R2 = {'a':'A','b':'B','c':'C'}
>>> composition(R1, R2)
{1: 'a', 2: 'b', 3: 'c'}

Example 2:

>>> R1 = {1 : [2, 3], 2 : [3], 3 : [4], 4 : [1, 3]}
>>> R2 = {1 : [3], 2 : [1, 4], 3 : [2], 4 : [1, 2]}
>>> composition(R1, R2)
{1: [1, 4, 2], 2: [2], 3: [1, 2], 4: [3, 2]}

CodePudding user response:

It's a little convoluted to write in Python using list comprehension alone (maybe readability can be a bit improved by using functools.reduce to collapse the sublists), but it should be something like this:

def composition(R1, R2):
  d = {
      i: [
          val
          for sublist in [R2[j] for j in R1[i]]
          for val in sublist
      ]
      for i in R1
  }

  print(d)
  • Related