'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