How can i add edges in graph (beginner) - python

i want to add edge to current graph
Here is my code for the graph
def mGraph():
graph = {'A': {'B': 1, 'C': 2},
'B': {'C': 2, 'D': 1},
'C': {'D': 1},
'D': {'C': 2},
'E': {'F': 1},
'F': {'C': 2}}
return graph
and here is the add edges function
def add_edge(graph, aa1, aa2):
graph[aa1].update()[aa2]
graph[aa2].update()[aa1]
return graph
i ask the user input first node and second node
def main():
graph = mGraph()
option = ''
while option != 'terminate':
print(" a. Display")
print(" c. Add Edges")
option = input("Enter your option:")
if option == "a":
print(graph)
if option == "c":
a1 = input("First Edge")
a2 = input("Second Edge")
print(add_edge(graph, a1, a2))
main()
i want to link two edges to current graph and want to modify them. if user enter A in "First Edge" and D in "Second Edge". i want see changes in the graph. user input should reflect on the graph.
i got error like this
Traceback (most recent call last):
File "C:......", line 52, in <module>
main()
File "C:......", line 49, in main
print(add_edge(graph, a1, a2))
File "C:......", line 25, in add_edge
graph[aa1].update()[aa2]
TypeError: 'NoneType' object is not subscriptable

Try this :
def add_edge(graph, aa1, aa2):
first_value = graph[aa1].copy()
for k,v in first_value.items():
if aa2 in k:
graph[aa1].update({aa2:v+1})
break
else:
graph[aa1].update({aa2:1})
second_value = graph[aa2].copy()
for k,v in second_value.items():
if aa1 in k:
graph[aa2].update({aa1:v+1})
break
else:
graph[aa2].update({aa1:1})
return graph

Related

I want to create a dict like this from input in python

all the contents must be inserted from the input
graph={
'A':{'B':3,'C':4},
'B':{'A':3,'C':5},
'C':{'B':5,'D':'1'},
'D':{'C':1},
}
Take the input in JSON format and then you can easily use json.loads to convert it to a dictionary.
>>> import json
>>> graph = json.loads(input("Enter graph as JSON: "))
Enter graph as JSON: {"A":{"B":3,"C":4},"B":{"A":3,"C":5},"C":{"B":5,"D":"1"},"D":{"C":1}}
>>> import pprint
>>> pprint.pprint(graph)
{'A': {'B': 3, 'C': 4},
'B': {'A': 3, 'C': 5},
'C': {'B': 5, 'D': '1'},
'D': {'C': 1}}
record_to_insert = int(input("num of record to insert :: "))
dic = {}
for i in range(record_to_insert):
print("")
key_name = input("parent key name :: ")
dic[key_name] = {}
print("Enter how many number of key,value pairs you want for key :: ",
key_name)
num_of_child_keyvalues_to_insert = int(input(""))
for k in range(num_of_child_keyvalues_to_insert):
key = input("child key name :: ")
value = input("Value name :: ")
dic[key_name][key] = value
print(dic)
def make_dict():
d = {}
while True:
key = input("Enter the key of dict or stay blank to finish adding key to this level of dict: ")
if key == "": # just stay blank to out from func
break
ch = input(f"Do you wanna to create nested dict for the key{key}? [y / <Press Enter for No>] ")
if ch == "y":
value = make_dict() # use recursion
else:
value = input(f"Enter the value for the key {key}: ")
d[key] = value
return d
print(make_dict())
link to screenshot

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)
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.
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': {}}
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)
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

Function to find the highest score path in a graph with python

I'm trying to make a function to find the highest score in a directed graph. I do have a start node and can't go throught the same node twice. I've tried to use recursive to get the sum of values until I hit one end node. Then I would call back my function to the start node and try other option ultil I hit another. And so on.
My problem is that when i return to a node with more than one path, the score value for this node is the sum of all paths it can take. And I only want the sum of one specific path.
Here is my code so far:
caminho = list()
def maxscore(start, parentals, score):
global caminho
parentals += start + '|'
if len(graph[start]) > 0:
for i in graph[start]:
if i not in parentals.split('|'):
value = graph[start][i]
if value:
score += value
func = maxscore(i, parentals, score)
else:
continue
if func[0] > score:
score = func[0]
caminho = parentals.split('|')
return score, caminho
else:
return score, start
graph = {
'a': {'b': 2, 'c': 4},
'b': {'d': 5},
'c': {'a': 1, 'e': 3},
'd': {'f': 4},
'e': {'b': 2, 'f': 3, 'g': 2},
'f': {},
'g': {}
}
print(maxscore('a', '', 0))
How could I make it work to return in the end only the best score with the path(caminho) it took.
Sorry if I couldn't make myself clear enough. Feel free to ask any questions.
You probably want to send the score variable by value, but you are sending it by reference, therefore all the possible paths' scores are added to it.
This is my approach:
def maxscore(start, parentals, score):
newParentals = parentals + start + '|'
print newParentals, score
scores = []
if graph[start]:
for nextNode in graph[start]:
if nextNode not in newParentals.split('|'):
scores.append(maxscore(nextNode, newParentals, score + graph[start][nextNode]))
return sorted(scores)[-1]
else:
return score
graph = {
'a': {'b': 2, 'c': 4},
'b': {'d': 5},
'c': {'a': 1, 'e': 3},
'd': {'f': 4},
'e': {'b': 2, 'f': 3, 'g': 2},
'f': {},
'g': {}
}
print(maxscore('a', '', 0))
And this is what gets printed:
a| 0
a|c| 4
a|c|e| 7
a|c|e|b| 9
a|c|e|b|d| 14
a|c|e|b|d|f| 18
a|c|e|g| 9
a|c|e|f| 10
a|b| 2
a|b|d| 7
a|b|d|f| 11
18
You can see how it checks all possible paths, and then picks the highest score :D
Here is an approach:
def maxscore(start, path, score):
best_score = -1
best_i = None
best_path = None
current_path = path + [start]
for i in graph[start]:
if not i in path:
score_i, path_i = maxscore(i, current_path, score + graph[start][i])
if score_i > best_score:
best_score = score_i
best_i = i
best_path = path_i
if best_i is None:
return score, current_path
else:
return best_score, best_path
graph = {
'a': {'b': 2, 'c': 4},
'b': {'d': 5},
'c': {'a': 1, 'e': 3},
'd': {'f': 4},
'e': {'b': 2, 'f': 3, 'g': 2},
'f': {},
'g': {}
}
print(maxscore('a', [], 0))
Output:
(18, ['a', 'c', 'e', 'b', 'd', 'f'])
Notes:
In the code of the question caminho and parentals served the same function. Just having a list is easier to work with than with a string.
In the for-loop, we test each of the edges. If the end-node of the edge is not yet in the path, we calculate the maximum score following that edge. We have to compare each of the possible edges and keep the one with the best score. We can only return from maxscore() after testing all possible edges.
If no free edge was found, we just return the current score and path
If free edges were found, we return the score and path of the best edge
PS: After revising the code, it can be shortened a bit. best_iis not really needed, and the test if best_i is None can be replaced by if best_path is None.
Also, if you need the path in the string form, you can print("|".join(best_path)).

Dijkstra's algorithm help in Python

Im having trouble with Dijkstra's algorithm in python. I understand how the Dijkstra's algorithm works, but im not that good in converting it into code. Is there any way to add the nodes of the path and print them out. I keep getting the path. Thank you.
import heapq
import sys
x = raw_input()
y = raw_input()
class Graph:
def __init__(self):
self.vertices = {}
def add_vertex(self, name, edges):
self.vertices[name] = edges
def shortest_path(self, start, finish):
distances = {} # Distance from start to node
previous = {} # Previous node in optimal path from source
nodes = [] # Priority queue of all nodes in Graph
for vertex in self.vertices:
if vertex == start: # Set root node as distance of 0
distances[vertex] = 0
heapq.heappush(nodes, [0, vertex])
else:
distances[vertex] = sys.maxint
heapq.heappush(nodes, [sys.maxint, vertex])
previous[vertex] = None
while nodes:
smallest = heapq.heappop(nodes)[1] # Vertex in nodes with smallest distance in distances
if smallest == finish: # If the closest node is our target we're done so print the path
path = []
while previous[smallest]: # Traverse through nodes til we reach the root which is 0
path.append(smallest)
smallest = previous[smallest]
return path
if distances[smallest] == sys.maxint: # All remaining vertices are inaccessible from source
break
for neighbor in self.vertices[smallest]: # Look at all the nodes that this vertex is attached to
alt = distances[smallest] + self.vertices[smallest][neighbor] # Alternative path distance
if alt < distances[neighbor]: # If there is a new shortest path update our priority queue (relax)
distances[neighbor] = alt
previous[neighbor] = smallest
for n in nodes:
if n[1] == neighbor:
n[0] = alt
break
heapq.heapify(nodes)
return distances
def __str__(self):
return str(self.vertices)
g = Graph()
g.add_vertex('A', {'B': 7, 'C': 8})
g.add_vertex('B', {'A': 7, 'F': 2})
g.add_vertex('C', {'A': 8, 'F': 6, 'G': 4})
g.add_vertex('D', {'F': 8})
g.add_vertex('E', {'H': 1})
g.add_vertex('F', {'B': 2, 'C': 6, 'D': 8, 'G': 9, 'H': 3})
g.add_vertex('G', {'C': 4, 'F': 9})
g.add_vertex('H', {'E': 1, 'F': 3})
print g.shortest_path(x, y)
So I was able to figure out how to use algorithm. Here what I came up with.
import heapq
x = raw_input()
y = raw_input()
def shortestPath(start, end):
queue,seen = [(0, start, [])], set()
while True:
(cost, v, path) = heapq.heappop(queue)
if v not in seen:
path = path + [v]
seen.add(v)
if v == end:
return cost, path
for (next, c) in graph[v].iteritems():
heapq.heappush(queue, (cost + c, next, path))
graph = {
'a': {'w': 14, 'x': 7, 'y': 9},
'b': {'w': 9, 'z': 6},
'w': {'a': 14, 'b': 9, 'y': 2},
'x': {'a': 7, 'y': 10, 'z': 15},
'y': {'a': 9, 'w': 2, 'x': 10, 'z': 11},
'z': {'b': 6, 'x': 15, 'y': 11},
}
cost, path = shortestPath(x, y)
print cost, path

Recursive code to create small shift dictionary

I have the following attempt at a recursive function to create a shift table within a dictionary:
def createShiftTable(alphabet,T,shiftT):
if not T:
for char in alphabet:
shiftT[char] = len(T)+1
return shiftT
else:
return createShiftTable(alphabet,T[1:],shiftT)
shiftT[T[0]] = len(T)
al=['a','b','c','d']
T = "aaabbdddaaba"
print(createShiftTable(al,T,{}))
This is returning {'a': 1, 'c': 1, 'b': 1, 'd': 1}
I'd like it to return {'a': 1, 'c': 13, 'b': 2, 'd': 5}
Non-recursively the following works ok but how do I get the above recursive function working?
def createShiftTableX(alphabet,T):
shiftT={}
for char in al:
shiftT[char] = len(T)+1
for i in range(len(T)):
shiftT[T[i]] = len(T)-i
return shiftT
al=['a','b','c','d']
T = "aaabbdddaaba"
print(createShiftTableX(al,T))
How about this:
def createShiftTableX(alphabet, T):
l = len(T)
for c in alphabet:
i = T.find(c)
if i<0:
yield l
else:
yield i+1
al=['a','b','c','d']
T = "aaabbdddaaba"
print(list(createShiftTableX(al,T)))
You should run this in a debugger or put in some logging or print statements to see what it is actually doing.

Categories

Resources