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.
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
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.
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