How do I delete an edge from a graph in Python - python

I'm reading ThinkComplexity book, I'm new to python, so I have this code:
class Graph(dict):
def __init__(self, vs=[], es=[]):
"""
:param vs: list of vertices/nodes in the graph
:param es: list of edges/connection for the nodes
:return: Object graph
"""
for v in vs:
self.add_vertex(v) #also node
for e in es:
self.add_edge(e) #arc/edge/line
def add_vertex(self, v):
"""
:param v: Add the node/vertex to the graph
:return: Nothing just add
"""
self[v] = {}
def add_edge(self, e):
"""
:param e: Add arc/edge/line to the graph here is in both directions as it is undirected graph, if there is a arc already replace it
:return: Nothing just add
"""
v, w = e
self[v][w] = e
self[w][v] = e
def get_edge(self, v1, v2):
try:
if self != None:
if self[v1][v2] == self[v2][v1]:
print 'got it'
return True
except:
return None
def remove_edge(self, e, e2):
try:
if self != None:
del self[e][e2]
del self[e2][e]
print 'deleted\n', e[0], e[1]
return True
except:
return None
def vertices(self): #get the list of nodes
nodes = []
for node in self.keys():
nodes.append(node.label)
print nodes, '\n'
return nodes
def edges(self):
list_edges = []
count = 0
for node in self:
for edges in self[node]:
count += 1
print self[node].values(), count
list_edges.append(self[node].values())
return list_edges
def out_vertices(self, v): #nodes connected to this node
connected = []
for node in v.keys():
connected.append(node)
print node, 'this node is connected to', v.keys()
return connected
def out_edges(self, v):
list_out_edges = []
for ed in v.values():
print ed, 'edges from to'
list_out_edges.append(ed)
return list_out_edges
class Vertex(object): #nodes fro the graph
def __init__(self, label=''):
self.label = label
def __repr__(self):
return 'Vertex/Node(%s)' % repr(self.label)
__str__= __repr__
class Edge(tuple):
def __new__(cls, e1, e2):
return tuple.__new__(cls, (e1, e2))
def __repr__(self):
return 'Edge(%s---%s) <-undirected' % (repr(self[0]), repr(self[1]))
__str__ = __repr__
In chapter 2 4. Write a method named remove_edge that takes an edge and removes all references to it from the graph.
I have the get_edge() code done, but t remove I don't know how to do it, any help?? This would be an starting point to do a Bayes Network, so I want to learn about python and graphs. Thanks

Like this:
def remove_edge(g, e, e2):
try:
if g != None:
del g[e][e2]
del g[e2][e]
print 'deleted\n', e[0], e[1]
return True
except:
return None
The keys in the dictionary can be objects, no only str. And need to do it both ways because is undirected

Related

Calculates the Kevin Bacon number of an actor in graph

I have made Queue Class and Graph classes
1st: Program a function
kevin_bacon_number(moviegraph, actor)
that calculates the Kevin Bacon number of an actor in your graph.
Testing: The code
g = Graph('movies.txt', False, '/')
kevin_bacon_number(g, 'De Niro, Robert')
should result in 1 (they were both in the same movie) and 2nd.
Program a function
actors_with_number(moviegraph, number)
That calculates the list of actors that have number as Kevin Bacon number.
Testing: The code
g = Graph('movies.txt', False, '/')
actors_with_number(g, 0)
should result in Bacon, Kevin. and 'De Niro, Robert' in actors_with_number(g, 1) should be True.
class Queue:
#-------------------------------------------------------------------
# Construct Queue object self as an empty Queue object.
def __init__(self):
self._first = None # Reference to first _Node
self._last = None # Reference to last _Node
self._length = 0 # Number of items
#-------------------------------------------------------------------
# Return True if self is empty, and False otherwise.
def isEmpty(self):
return self._first is None
#-------------------------------------------------------------------
# Add item to the end of self.
def enqueue(self, item):
oldLast = self._last
self._last = _Node(item, None)
if self.isEmpty():
self._first = self._last
else:
oldLast.next = self._last
self._length += 1
#-------------------------------------------------------------------
# Remove the first item of self and return it.
def dequeue(self):
item = self._first.item
self._first = self._first.next
if self.isEmpty():
self._last = None
self._length -= 1
return item
#-------------------------------------------------------------------
# Return the number of items in self.
def __len__(self):
return self._length
#-------------------------------------------------------------------
# Return a string representation of self.
def __str__(self):
s = ''
cur = self._first
while cur is not None:
s += str(cur.item) + ' '
cur = cur.next
return s
#----------------------------------------------------------------------
A _Node object references an item and a next _Node object.
A Queue object is composed of _Node objects.
class _Node:
def __init__(self, item, next):
self.item = item # Reference to an item
self.next = next # Reference to the next _Node object
class Graph:
# Construct a new Graph object. If a filename is specified,
# populate the Graph object by reading data from the specified
# file with the specified delimiter.
# For directed graphs the argument directed should get value True
def __init__(self, filename=None, directed=False, delimiter=None):
self._directed = directed
self._e = 0
self._adj = dict()
if filename is not None:
f = open(filename, 'r')
lines = f.read().split('\n')
for line in lines:
names = line.split(delimiter)
for i in range(1, len(names)):
self.addEdge(names[0], names[i])
line = ''
# Add an edge to self between vertex v and vertex w.
def addEdge(self, v, w):
if not self.hasVertex(v): self._adj[v] = set()
if not self.hasVertex(w): self._adj[w] = set()
if not self.hasEdge(v, w):
self._e += 1
self._adj[v].add(w)
if not self._directed: self._adj[w].add(v)
# Return an iterable collection containing all neighbors of
# vertex v in self.
def adjacentTo(self, v):
return iter(self._adj[v])
# Return an iterable collection of all vertices in self.
def vertices(self):
return iter(self._adj)
# Return True if vertex v is in self, and False otherwise.
def hasVertex(self, v):
return v in self._adj
# Return True if v-w is an edge in self, and False otherwise.
def hasEdge(self, v, w):
return w in self._adj[v]
# Return the number of vertices in self.
def countV(self):
return len(self._adj)
# Return the number of edges in self.
def countE(self):
return self._e
# Return the degree of vertex v of self.
def degree(self, v):
return len(self._adj[v])
# Return a string representation of self.
def __str__(self):
s = ''
for v in self.vertices():
s += v + ' '
for w in self.adjacentTo(v):
s += w + ' '
s += '\n'
return s

Python: Heapify a list of tuples (Dijkstra's Algo)

Here is my code for Dijkstra's Algorithm.
I have declared a "Vertex" class and a "Graph" class.
I am using heapq module and heapifying the list "unvisitedQueue" of tuples. But even then an error shows up saying " TypeError: '<' not supported between instances of 'Vertex' and 'Vertex' " even when "v.getDistance()" returns either 0 or float('inf').
import heapq
class Vertex:
def __init__(self, node):
self.id = node
self.adjacent = {}
self.previous = None
self.distance = float('inf')
def addNeighbor(self, neighbor, weight = 0):
self.adjacent[neighbor] = weight
def getConnections(self):
return self.adjacent.keys()
def getVertex_ID(self):
return self.id
def getWeight(self, neighbor):
return self.adjacent[neighbor]
def setDistance(self, dist):
self.distance = dist
def getDistance(self):
return self.distance
def setPrevious(self, prev):
self.previous = prev
def __str__(self):
return str(self.id) + "adjacent : " + str([x.id for x in self.adjacent])
class Graph:
def __init__(self):
self.vertDictionary = {}
self.numVertices = 0
def __iter__(self):
return iter(self.vertDictionary.values())
def addVertex(self, node):
self.numVertices += 1
newVertex = Vertex(node)
self.vertDictionary[node] = newVertex
return newVertex
def getVertex(self, node):
if node in self.vertDictionary:
return self.vertDictionary[node]
else:
return None
def addEdge(self, frm, to, cost = 0):
if frm not in self.vertDictionary:
self.addVertex(frm)
if to not in self.vertDictionary:
self.addVertex(to)
self.vertDictionary[frm].addNeighbor(self.vertDictionary[to], cost)
self.vertDictionary[to].addNeighbor(self.vertDictionary[frm], cost)
def getVertices(self):
return self.vertDictionary.keys()
def setPrevious(self, current):
self.previous = current
def getPrevious(self):
return self.previous
def getEdges(self):
edges = []
for v in G:
for w in v.getConnections():
v_id = v.getVertex_ID()
w_id = w.getVertex_ID()
edges.append((v_id, w_id, v.getWeight(w)))
return edges
def Dijkstra(G, s):
source = G.getVertex(s)
source.setDistance(0)
visited = {}
unvisitedQueue = [(v.getDistance(), v) for v in G]
heapq.heapify(unvisitedQueue)
while len(unvisitedQueue):
uv = heapq.heappop(unvisitedQueue)
currVert = uv[1]
visited[currVert] = True
for nbr in currVert.getConnections():
if currVert.getDistance() + currVert.getWeight(nbr) < nbr.getDistance():
nbr.setDistance(currVert.getDistance() + currVert.getWeight(nbr))
print("Updated: Current = %s Neighbour = %s New Distance = %s" %(currVert.getVertex_ID(), nbr.getVertex_ID(), nbr.getDistance()))
else:
print("Not Updated: Current = %s Neighbour = %s Distance = %s" %(currVert.getVertex_ID(), nbr.getVertex_ID(), nbr.getDistance()))
while len(unvisitedQueue):
heapq.heappop(unvisitedQueue)
unvisitedQueue = [(v.getDistance(), v) for v in G if v not in visited]
heapq.heapify(unvisitedQueue)
for v in G:
print(source.getVertex_ID(), "to", v.getVertex_ID(), "-->", v.getDistance())
ERROR -->
Traceback (most recent call last):
File "d:\Python\Final 450\Graph\Dijkstra's_Algo.py", line 124, in <module>
print(Dijkstra(G, "a"))
File "d:\Python\Final 450\Graph\Dijkstra's_Algo.py", line 86, in Dijkstra
heapq.heapify(unvisitedQueue)
TypeError: '<' not supported between instances of 'Vertex' and 'Vertex'
The error is happening because tuples are compared lexicographically. If two distances are the same, the comparison moves on to the Vertex objects themselves.
Two solutions readily come to mind. The first is simply to add a unique index to the tuple before the Vertex but after the distance. This is easy, and would work even if you didn't have access to the Vertex class:
unvisitedQueue = [(v.getDistance(), i, v) for i, v in enumerate(G) if v not in visited]
The second option is to modify Vertex to have a __lt__ magic method:
def __lt__(self, other):
return self.getDistance() < other.getDistance()
This is nice because you can heapify more directly now:
unvisitedQueue = [v for v in G if v not in visited]

Calculating the centrality degree on a graph

I have to calculate the centrality degree on a graph. My implementation is:
import csv
class Graph:
'''
Representation of a simple graph using an adjacency map.
There exist nested Classes for Vertex and Edge objects and
useful methods for vertex and edge, edge incidence and
vertex degree retrieval plus edge and vertex insertion
'''
# == Class Vertex == #
class Vertex:
'''
Class for representing vertex structure for a graph.
'''
__slots__ = '_element'
def __init__(self, x):
'''
Do not call constructor directly. Use Graph's insert_vertex(x).
'''
self._element = x
def element(self):
'''
Return element associated with this vertex.
'''
return self._element
def __hash__(self):
'''
will allow vertex to be a map/set key
'''
return hash(self._element)
def __repr__(self):
return '{0}'.format(self._element)
def __eq__(self, other):
if isinstance(other, Graph.Vertex):
return self._element == other._element
return False
# == Class Edge == #
class Edge:
'''
Class for representing edge structure for a graph.
'''
__slots__ = '_origin', '_destination', '_weight'
def __init__(self, u, v, x):
'''
Do not call constructor directly. Use Graph's insert_edge(x).
'''
self._origin = u
self._destination = v
self._weight = x
def endPoints(self):
'''
Return (u,v) tuple for vertices u and v.
'''
return (self._origin, self._destination)
def opposite(self, v):
'''
Return the vertex that is opposite v on this edge.
'''
return self._destination if self._origin == v else self._origin
def element(self):
'''
Return element associated with this edge.
'''
return self._weight
def __hash__(self):
'''
will allow edge to be a map/set key
'''
return hash((self._origin, self._destination))
def __repr__(self):
if self._weight is None:
return '({0}, {1})'.format(self._origin, self._destination)
return '({0}, {1}, {2})'.format(self._origin, self._destination, self._weight)
# == Class Graph == #
def __init__(self, directed=False):
'''
Create an empty graph (undirected, by default).
Graph is directed if optional parameter is set to True.
'''
self._outgoing = {}
self._incoming = {} if directed else self._outgoing
def __getitem__(self, arg):
return self._incoming[arg]
def is_directed(self):
'''
Return True if graph is directed
'''
return self._outgoing is not self._incoming
def vertex_count(self):
'''
Return the vertices count
'''
return len(self._outgoing)
def vertices(self):
'''
Return an iterator over the graph's vertices
'''
return self._outgoing.keys()
def get_vertex(self, el):
'''
Return the graph's vertex with corresponding element
equal to el. Return None on failure
'''
for vertex in self.vertices():
if vertex.element() == el:
return vertex
return None
def edges_count(self):
'''
Return the edges count
'''
edges = set()
for secondary_map in self._outgoing.values():
edges.update(secondary_map.values())
return len(edges)
def edges(self):
'''
Return a set of graph's edges
'''
edges = set()
for secondary_map in self._outgoing.values():
edges.update(secondary_map.values())
return edges
def get_edge(self, u, v):
'''
Return the edge from u to v
'''
return self._outgoing[u].get(v)
def degree(self, v, outgoing=True):
'''
Return the number of incident vertices to v
If graph is directed then handle the case of indegree
'''
inc = self._outgoing if outgoing else self._incoming
return len(inc[v])
def incident_edges(self, v, outgoing=True):
'''
Return all incident edges to node v.
If graph is directed, handle the case of incoming edges
'''
inc = self._outgoing if outgoing else self._incoming
if v not in inc:
return None
for edge in inc[v].values():
yield edge
def adjacent_vertices(self, v, outgoing=True):
'''
Return adjacent vertices to a given vertex
'''
if outgoing:
if v in self._outgoing:
return self._outgoing[v].keys()
else:
return None
else:
if v in self._incoming:
return self._incoming[v].keys()
else:
return None
def insert_vertex(self, x=None):
'''
Insert and return a new Vertex with element x
'''
for vertex in self.vertices():
if vertex.element() == x:
# raise exception if vertice exists in graph
# exception can be handled from the class user
return vertex
v = self.Vertex(x) # cria um objeto do tipo Vertex
self._outgoing[v] = {}
if self.is_directed:
self._incoming[v] = {}
return v
def insert_edge(self, u, v, x=None):
'''
Insert and return a new Edge from u to v with auxiliary element x.
'''
if (v not in self._outgoing) or (v not in self._outgoing):
# raise exception if one of vertices does not exist
# exception can be handled from the class user
raise Exception('One of the vertices does not exist')
if self.get_edge(u, v):
# no multiple edges
# exception can be handled from the class user
e = self.Edge(u, v, x)
return e
e = self.Edge(u, v, x) # cria um objeto do tipo Edge
self._outgoing[u][v] = e
self._incoming[v][u] = e
return e
def remove_edge(self, u, v):
if not self.get_edge(u, v):
# exception for trying to delete non-existent edge
# can be handled from class user
raise Exception('Edge is already non-existent.')
u_neighbours = self._outgoing[u]
del u_neighbours[v]
v_neighbours = self._incoming[v]
del v_neighbours[u]
def remove_vertex(self, x):
'''
Delete vertex and all its adjacent edges from graph
'''
if (x not in self._outgoing) and (x not in self._incoming):
raise Exception('Vertex already non-existent')
secondary_map = self._outgoing[x]
for vertex in secondary_map:
# delete reference to incident edges
if self.is_directed():
del self._incoming[vertex][x]
else:
del self._outgoing[vertex][x]
# delete reference to the vertex itself
del self._outgoing[x]
def printG(self):
'''Mostra o grafo por linhas'''
print('Grafo Orientado:', self.is_directed())
'''Mostra o número de vertices'''
print("Número de Vertices: {}".format(G.vertex_count()))
'''Mostra o número de arestas'''
print("Número de Arestas: {}".format(G.edges_count()))
for v in self.vertices():
print('\nUser: ', v, ' grau_in: ', self.degree(v, False), end=' ')
if self.is_directed():
print('grau_out: ', self.degree(v, False))
for i in self.incident_edges(v):
print(' ', i, end=' ')
if self.is_directed():
for i in self.incident_edges(v, False):
print(' ', i, end=' ')
My graph is constructed from a CSV file:
def read_csv(filename):
G = Graph() # cria um objeto do tipo Graph
with open(filename, 'r') as csv_file: # abre o ficheiro csv
data = csv.reader(csv_file)
next(data) # ignora a primeira coluna do ficheiro
for linha in data: # por cada linha no ficheiro
id_origem = linha[0] # a origem é a primeira coluna do ficheiro
id_destino = linha[1] # o destino é a segunda coluna do ficheiro
peso = linha[2] if len(linha) > 2 else 1 # se não existir uma terceira coluna do ficheiro
# assume-se que o peso das arestas, é 1
v_origem = G.insert_vertex(id_origem) # insere o vertex no grafo
v_destino = G.insert_vertex(id_destino) # insere o vertex no grafo
G.insert_edge(v_origem, v_destino, int(peso)) # insere a aresta no grafo
return G
CSV file has the structure:
follower,followed,distance
Murphy,Thornton,45
Perkins,Walters,26
Perkins,Bradley,7
Lawrence,Hart,15
The shortest distance are calculated by:
def shortest_path_lengths(g, src):
d = {}
cloud = {}
pq = AdaptableHeapPriorityQueue()
pqlocator = {}
source = Graph.Vertex(src)
for v in G.vertices():
if v == source:
d[v] = 0
else:
d[v] = float('inf')
pqlocator[v] = pq.add(d[v], v)
while not pq.is_empty():
key, u = pq.remove_min()
cloud[u] = key
del pqlocator[u]
for e in G.incident_edges(u):
v = e.opposite(u)
if v not in cloud:
wgt = e.element()
if d[u] + wgt < d[v]:
d[v] = d[u] + wgt
pq.update(pqlocator[v], d[v], v)
return cloud
I'm calculating the centrality degree from:
def centrality_degree(G, src=None):
distances = []
closeness_centr = []
short = shortest_path_lengths(G, src)
#print(short)
vertex_number = G.vertex_count()
#while contador <= len(short):
#for vertex in G.vertices(): #G.adjacent_vertices(G.get_vertex(src)):
for value in short.values():
if value != float('inf'):
distances.append(value)
print(distances)
soma = sum(distances)
#print(soma)
formula = (vertex_number-1)/soma
closeness_centr.append(formula)
print(closeness_centr)
Is there any way to caculate the centrality degree without passing the parameter src?
Try:
def centrality_degree(G):
n_vertex = ...
# compute all the shortest paths from the node i to j
# (do a for in a for)
degree = ...
return degree

Using a swap method within a Positional Linked List class without creating new nodes.

wise ones. I am having difficulties implementing a swap method within a Positional Linked List class. The swap method will take input of two positions, "p" and "q" that will swap the positions and re-link the existing nodes. Any help is appreciated.
This is what I have so far:
def swap(self, p, q): # Problem 7.34
valid_position = self._validate(p)
valid_position2 = self._validate(q)
element_p = valid_position._element
element_q = valid_position2._element
position_next = valid_position._next
position_prev = valid_position._prev
valid_position._next = valid_position2._next
valid_position._prev = valid_position2._prev
valid_position2._next = position_next
valid_position2._prev = position_prev
valid_position._element = element_q
valid_position2._element = element_p
and it works for some cases but not all. I've been thinking about the header and trailer nodes and the various conditions that this applies to but am having lots of trouble.
This is the class Positional Linked List which inherits from a Doubly Linked List.
# Abstract Data Type : Positional List
# A positional list PL supports
# len(PL)
# PL.is_empty()
# Accessor Methods (getters)
# iter(PL) : Return a forward iterator (uses yield)
# PL.first(), PL.last() : Return position of first (last) element, or None
# if empty
# PL.before(p), PL.after(p) : Return the position immediately before (after) p,
# or None if p is first (last)
# Mutators Methods (setters)
# PL.add_first(e), PL.add_last(e) : Insert new element e in front (back) and return position
# PL.add_before(p, e), PL.add_after(p, e) : Insert new element e just before (after) p, return
# position
# PL.delete(p) : Remove and return element at position p. Also invalidates position p.
# PL.replace(p, e) : Replace and return element replaced at position p.
from DoublyLinkedList import _DoublyLinkedList as dlb
class PositionalList(dlb):
# ------ nested Position class ---------------
class Position:
def __init__(self, container, node):
self._container = container # reference to linked list that
contains
# node at this position
self._node = node # reference to node pointed to by
# this position
def element(self):
return self._node._element
def __eq__(self, other):
"""Return True if other is a Position representing teh same
location as self."""
return type(other) is type(self) and other._node is self._node
def __ne__(self, other): # !=
return not (self == other)
# --------------- private position Validation method
# possible errors: p is not a Position, p is not in the current list, p
# is no longer valid
# purpose of method: return the node pointed to by p if p is a valid
# position
# self in this scope refers to an instance of a doubly linked list
def _validate(self, p):
"""Return position's node, or raise an exception."""
if not isinstance(p, self.Position):
raise TypeError("p must be of type Position.")
# if the list that contains p is not in the current list raise
# ValueError
if p._container is not self:
raise ValueError("p does not belong to this container.")
if p._node._next is None: # means underlying node has been
invalidated
raise ValueError("p is no longer valid.")
return p._node
# --------------- private method to create a position
def _make_position(self, node):
"""Return Poisition instance for a given node, None if node is a
sentinel."""
if node is self.header or node is self.trailer:
return None
else:
return self.Position(self, node)
# ----------------- accessor methods -------------------------
def first(self):
return self._make_position(self.header._next)
def last(self):
return self._make_position(self.trailer._prev)
def before(self, p):
node = self._validate(p)
return self._make_position(node._prev)
def after(self, p):
node = self._validate(p)
return self._make_position(node._next)
def __iter__(self):
"""Forward iterator of list elements."""
# Allows the use of next()
# Allows embedding into for loops
pointer = self.first()
while pointer is not None:
yield pointer.element() #return element stored at this position
pointer = self.after(pointer) # moves the pointer "forward"
def __reversed__(self): # Problem 7.15
"""Backward iterator of list elements."""
pointer = self.last()
while pointer is not None:
yield pointer.element()
pointer = self.before(pointer)
def find(self, e): # Problem 7.13
pointer = self.first()
while e != pointer.element():
if e == pointer.element():
return pointer.element()
pointer = pointer.after(pointer)
# --------------- mutator methods
# override the _insert_between() from parent _DoublyLinkedList class
# to allow returning a position rather than a node
def _insert_between(self, e, predecessor, successor):
node = super().insert_between(e, predecessor, successor)
return self._make_position(node)
def add_first(self, e):
"""Insert new element e in front and return a position."""
return self._insert_between(e, self.header, self.header._next)
def add_last(self, e):
return self._insert_between(e, self.trailer._prev, self.trailer)
def add_before(self, p, e):
valid_position = self._validate(p)
return self._insert_between(e, valid_position._prev, valid_position)
def add_after(self, p, e):
valid_position = self._validate(p)
return self._insert_between(e, valid_position, valid_position._next)
def delete(self, p):
"""Remove and return element at position p. Invalidate position
p."""
valid_position = self._validate(p)
#p._container = None
return self.delete_node(valid_position)
def replace(self, p, e):
"""Replace and return element at position p."""
valid_position = self._validate(p)
element_to_return = valid_position._element
valid_position._element = e
return element_to_return
def swap(self, p, q): # Problem 7.34
valid_position = self._validate(p)
valid_position2 = self._validate(q)
element_p = valid_position._element
element_q = valid_position2._element
position_next = valid_position._next
position_prev = valid_position._prev
valid_position._next = valid_position2._next
valid_position._prev = valid_position2._prev
valid_position2._next = position_next
valid_position2._prev = position_prev
valid_position._element = element_q
valid_position2._element = element_p
This is the Doubly Linked List class:
# Abstract Data Type: Doubly Linked List
# A doubly linked list dll supports
# dll.is_empty()
# len(dll)
# dll.insert_between(e, predecessor, successor)
# dll.delete_node(a_node): should not delete the header and trailer nodes
# We will implement this class as an abstract class
# Meaning it is meant to be inherited by other data structures rather than
# instantiated directly
class _DoublyLinkedList(object):
class _Node:
# nested _Node class------------------------------------------------
__slots__ = '_element', '_prev', '_next'
def __init__(self, element, previous, next_): # next is a reserved
# word, hence underscore
self._element = element
self._prev = previous
self._next = next_
class Empty(Exception):
pass
#-----------------------------------------------------------------------
def __init__(self):
self.header = self._Node(None, None, None)
self.trailer = self._Node(None, None, None)
self.header._next = self.trailer
self.trailer._prev = self.header
self.size = 0
def __len__(self):
return self.size
def is_empty(self):
return self.size == 0
def insert_between(self, e, predecessor, successor):
new_node = self._Node(e, predecessor, successor)
predecessor._next = new_node
successor._prev = new_node
self.size += 1
return new_node
def delete_node(self, a_node):
"""Should not delete sentinels."""
# Error management POTENTIAL EXAM QUESTION so that it doesn't delete
# sentinels
# if a_node == self.header or a_node == self.trailer:
# return Err
prev_ = a_node._prev
next_ = a_node._next
prev_._next = next_
next_._prev = prev_
temp = a_node._element
a_node._prev = a_node._next = None
self.size -= 1
return temp
def middle(self):
n = self.header._next
m = self.trailer._prev
if n == self.trailer:
return None
while n != m:
n = n._next
m = m._next
return m
def printLinkedList(self):
node = self.header
while node is not None:
print(node._next)
node = node._next
def reverse(self):
current = self.header
while current is not None:
temp = current._prev
current._prev = current._next
current._next = temp
current = current.prev
if __name__ == "__main__":
pl = PositionalList()
# Add 2, 3, 4, 1
p2 = pl.add_first(2)
p3 = pl.add_after(p2, 3)
p4 = pl.add_after(p3, 4)
p1 = pl.add_after(p4, 1)
pl.find(4)

Making a graph class iterate using a dictionary

I am trying to build a iterable graph class with python 2.7. I want to be able to iterate though a dictionary containing the vertexes.
Cutting and pasting from https://github.com/joeyajames has got me so far but now I am confused as to how to make this work so that
I can test vertices dict for the presence of an vertice and add if not present. This part is maybe unneeded.
"if (a not in gra ):" because the validation is done in the Graph class itself.
The expected output is a dictionary with the vertices as keys. Actualy im not even sure a list is not better object to use.
class Vertex(object):
def __init__(self, n):
self.name = n
self.neighbors = list()
self.discovery = 0
self.finish = 0
self.color = 'black'
def add_neighbor(self, v):
if v not in self.neighbors:
self.neighbors.append(v)
self.neighbors.sort()
class Graph(object):
def __init__(self,size):
self.vertices = {}
self.hops = 0
self.count = 0
self.limit = size
def __iter__(self):
return self
def next(self):
self.count += 1
if self.count > self.limit:
raise StopIteration
def add_vertex(self,vertex):
if isinstance(vertex, Vertex) and vertex.name not in self.vertices:
self.vertices[vertex.name] = vertex
return True
else:
return False
def add_edge(u,v):
if u in self.vertices and v in self.vertices:
for key, value in self.vertices.items():
if key == u:
value.add_neighbor(v)
if key == v:
value.add_neighbor(u)
return True
else:
return False
def _dfs(self, vertex):
global hops
vertex.color = 'red'
vertex.discovery = hops
hops += 1
for v in vertex.neighbors:
if self.vertices[v].color == 'black':
self._dfs(self.vertices[v])
vertex.color = 'blue'
vertex.finish = hops
time += 1
input = ((5,3),(4 ,2),(0,1),(2 3),(0 4))
N,l = input[0]
print "N is " + str(N)
print "l is " + str(l)
gra = Graph(N)
for i in xrange(1,l):
a,b = input[i]
# Store a and b as vertices in graph object
print "a is " + str(a) + " b is " + str(b)
if (a not in gra ):
print "adding a"
gra.add_vertex(Vertex(chr(a)))
if (b not in gra ):
print "adding b"
gra.add_vertex(Vertex(chr(b)))
You are trying to use not in, which tests for containment; implement the __contains__ hook to facilitate that:
def __contains__(self, vertex):
return vertex.name in self.vertices
I've assumed you wanted to test for vertices, so create one before testing for containment:
a = Vertex(chr(a))
if a not in gra:
print "adding a"
gra.add_vertex(a)
For iteration, I'd not make Graph itself the iterator; that limits you to iterating just once. Your next() method also lacks a return statement, so all you are doing is produce a sequence of None objects.
Make it an iterable instead, so return a new iterator object each time __iter__ is called. You can most simply achieve this by making __iter__ a generator:
def __iter__(self):
for vertex in self.vertices.itervalues():
yield vertex
Note the yield. I've assumed you wanted to iterate over the vertices.

Categories