Checking if set of elements can jointly create parent element

Question:

I have a dictionary with all elements and their children.

For example, looking at the python dictionary below:

product_dict = {
        'A': {'B', 'C', 'D'},
        'B': {'E', 'F'},
        'C': {'G'},
        'D': {},
        'E': {'H', 'I'}
    }

By the dict we can infer that, for example:

  • B, C and D create A.
  • E, F, G and D also create A.
  • H, I, F, G and D also create A, etc…

What would be the best way to create a function that would return if any given set of elements can create another element, i.e. Can {‘H’,’I’,’F’,’G’,’D’} create’A’?

I am using Python and I think recursion would be the best way to crack this problem but, being a newbie in it myself, I am open to any other types of algorithms which would help me solve this case.

Asked By: Frederico Portela

||

Answers:

Recursion is indeed natural for this, since we’re essentially exploring the branches of a tree.

The recurrence formula is roughly: "The target is already in the resources; or all of the children of the target can be produced recursively from these resources".

Important note: you have 'D': {} in your dict, which means that 'D' can be created from nothing. This is very different from not having 'D' in the dict, which would have meant that 'D' cannot be created.

product_dict = {
        'A': {'B', 'C', 'D'},
        'B': {'E', 'F'},
        'C': {'G'},
        'D': {},
        'E': {'H', 'I'}
    }

def can_create(target, resources, product_dict=product_dict):
    return (
        (target in resources) or
        (
            target in product_dict and
            all(can_create(child, resources, product_dict)
                for child in product_dict[target])
        )
    )

for resources in map(set, ('A', 'B', 'BCD', 'EFGD', 'HIFG', 'HIFGD')):
    result = can_create('A', resources)
    print('{:25s} {} create A'.format(str(resources), 'can' if result else 'cannot'))

del product_dict['D']
print('nNow we remove D from the dict and try again.n')

for resources in map(set, ('A', 'B', 'BCD', 'EFGD', 'HIFG', 'HIFGD')):
    result = can_create('A', resources)
    print('{:25s} {} create A'.format(str(resources), 'can' if result else 'cannot'))

Output:

{'A'}                     can create A
{'B'}                     cannot create A
{'D', 'C', 'B'}           can create A
{'D', 'E', 'F', 'G'}      can create A
{'I', 'F', 'H', 'G'}      can create A
{'D', 'H', 'I', 'F', 'G'} can create A

Now we remove D from the dict and try again.

{'A'}                     can create A
{'B'}                     cannot create A
{'D', 'C', 'B'}           can create A
{'D', 'E', 'F', 'G'}      can create A
{'I', 'F', 'H', 'G'}      cannot create A
{'D', 'H', 'I', 'F', 'G'} can create A
Answered By: Stef
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.