'Dictionary/recursive/ counting parts (exercise[LOGIC])
problem: create a recursive function that given an input key, would return the amount of basic components to build the given input key.
EX 1) input = "Engine" output = Engine ==> metal: 3, rubber: 2
EX 2) input = "metal" output = metal ==> metal: 1
EX 3) input = "piston" output = piston ==> metal: 1, rubber: 1
car= {
"Engine" : ["pistons", "timing belt", "metal" ,"metal"],
"Pistons" : ["Metal", "rubber"],
"timing belt" : ["rubber"],
"metal" : [],
"rubber" : []
}
my code has different variable names and key name, but it's the same idea
parts = {
'A': ['B', 'B', 'C'],
'B': [],
'C': ['D','E','F'],
'D': [],
'E': ['B','D'],
'F': []
}
#above here its user input
counter_dictio = {
'A': [],
'B': [],
'C': [],
'D': [],
'E': [],
'F': []
}
def desamble(key, dictionary):
#check if array is empty
#ccounter +=1
if (len(dictionary[key])) == 0:
counter_dictio[key].append(key)
#if array is populated
#enter to this array
#desample(i, dictionary)
else:
for i in dictionary[key]:
desamble(i, dictionary)
key = "A"
desamble(key, parts)
Solution 1:[1]
One way to go is:
from collections import Counter
car= {
"engine": ["pistons", "timing belt", "metal", "metal"],
"pistons": ["metal", "rubber"],
"timing belt": ["rubber"],
"metal": [],
"rubber": []
}
def ingredients(key, dct):
if dct[key] == []:
yield key
else:
for sub_part in dct[key]:
yield from ingredients(sub_part, dct)
print(*ingredients('engine', car)) # metal rubber rubber metal metal
print(Counter(ingredients('engine', car))) # Counter({'metal': 3, 'rubber': 2})
ingredients makes a generator of ingredients, so you can use Counter to count them.
Solution 2:[2]
Here is code that will group by your components
from collections import defaultdict
parts = {
'A': ['B', 'B', 'C'],
'B': [],
'C': ['D', 'E', 'F'],
'D': [],
'E': ['B', 'D'],
'F': []
}
result = defaultdict(dict)
for k, v in parts.items():
row = result[k] # used to create empty dict on initial empty list
for item in v:
if row.get(item) is None:
row[item] = 1
else:
row[item] += 1
This will result in following dict
{'A': {'B': 2, 'C': 1}, 'B': {}, 'C': {'D': 1, 'E': 1, 'F': 1}, 'D': {}, 'E': {'B': 1, 'D': 1}, 'F': {}}
Solution 3:[3]
another solution without using recursively, and for a predetermined list would be:
#==== user input====
key = "E"
parts = {
'A': ['B', 'B', 'C'],
'B': [],
'C': ['D','E','F'],
'D': [],
'E': ['B','D'],
'F': []
}
#====end user input=====
#Function for the predetermined dictionary
def desamble(key, dictionary):
if key == "B" or key == "D" or key == "F":
print(key + "==> " + key + ": 1")
elif key == "E":
print(key + "==> " + "B: 1, D: 1" )
elif key == "C":
print(key + "==> " + "B: 1, D: 2, F: 1" )
elif key == "A":
print(key + "==> " + "B: 3, D: 2, F: 1" )
else:
print("Key " + key + " is not defined in dictionary")
#====end====
desamble(key, parts)
Solution 4:[4]
Another recursive way to solve this problem, adding a solution for the problem of circularity, meaning that in case that the parts call to eachother. EX)
dictionary = {
"A": "B",
"B": "A"
}
from typing iport Counter
def func(key, dictionary, current=None):
if not current:
current = set() # could also be a list
if key in current:
raise ValueError # or whichever
if not dictionary.get(key):
return [key]
ret = []
for subkey in dictionary[key]:
ret.extend(func(subkey, dictionary, current.union({key})))
return ret
Print(Counter(func("A"), parts))
#by officerthegeeks
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | sudden_appearance |
| Solution 3 | Yuan Shih |
| Solution 4 | Yuan Shih |
