Making a graph class iterate using a dictionary - python

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.

Related

CSP Recursive Calls Fail with with Range(a,b) but not Explicit Range

Sudoku is a well known CSP and, in this case, LC problem. I don't need the solution, which follows.
My question is why does self.DOMAIN = "123456789" (line #4) work, whereas self.DOMAIN = map(str, range(1, 10)) (line #5) does not? Are they not equivalent?
class Solution:
def __init__(self):
self.SIZE = 9
# self.DOMAIN = map(str, range(1, self.SIZE + 1)) # THIS DES NOT WORK NOT WORK
self.DOMAIN = "123456789" # THIS WORKS
self.EMPTY = "."
from collections import defaultdict
self.rows = defaultdict(set) # {row:set}
self.cols = defaultdict(set) # {col:set}
self.boxs = defaultdict(set) # {box:set}
self.row_idx = lambda cell: cell // self.SIZE # determines row from cell num
self.col_idx = lambda cell: cell % self.SIZE # determins col from cell num
self.box_idx = lambda r, c: (r // 3) * 3 + c // 3 # determines box from row, col
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
assert(len(board) == self.SIZE and len(board[0]) == self.SIZE), \
"Sudoku board must be 9x9 in dimensions"
# Initialize board state
self.board = board
for r in range(self.SIZE):
for c in range(self.SIZE):
val = self.board[r][c]
if val != self.EMPTY:
self.rows[r].add(val)
self.cols[c].add(val)
self.boxs[self.box_idx(r, c)].add(val)
# Begin backtracking search from the first cell
self.backtrack(0)
def backtrack(self, cell):
if cell == 81:
# all values have been set and we are outside the board range
return True
r, c = self.row_idx(cell), self.col_idx(cell)
if self.board[r][c] != self.EMPTY:
# nothing to do, continue search
return self.backtrack(cell + 1)
# explore values in the domain for this cell
for candidate_val in self.DOMAIN:
if self.is_valid(r, c, candidate_val):
# place candidate
self.board[r][c] = candidate_val
self.rows[r].add(candidate_val)
self.cols[c].add(candidate_val)
self.boxs[self.box_idx(r, c)].add(candidate_val)
# continue search
if self.backtrack(cell + 1):
return True
# remove candidate and backtrack
self.board[r][c] = self.EMPTY
self.rows[r].remove(candidate_val)
self.cols[c].remove(candidate_val)
self.boxs[self.box_idx(r, c)].remove(candidate_val)
# no solution found for all values in the domain for this cell
return False
def is_valid(self, r, c, val):
""" Returns whether a value can be placed in board[r][c] in the current game state """
if val in self.rows[r]:
return False
if val in self.cols[c]:
return False
if val in self.boxs[self.box_idx(r, c)]:
return False
return True
You are suffering confusion between "generator" and "container".
Consult type( ... ) to tell the difference between them.
Python generators are "lazy", for excellent technical reasons.
Sometimes we can get away with just evaluating
the first K items of an infinite generator.
In your method you want everything greedily pulled out,
and then stored in a container.
The conventional way to phrase this is to wrap map with list:
self.DOMAIN = list(map(str, range(1, 10)))
or perhaps in your case you would prefer that .join pull them out:
self.DOMAIN = ''.join(map(str, range(1, 10)))

Python list of classes , index() not working

Not sure what i'm doing wrong here. I have this class:
class Node:
'''
Class to contain the lspid seq and all data.
'''
def __init__(self, name,pseudonode,fragment,seq_no,data):
self.name = name
self.data = {}
self.pseudonode = pseudonode
self.seq_no = seq_no
self.fragment = fragment
def __unicode__(self):
full_name = ('%s-%d-%d') %(self.name,self.pseudonode,self.fragment)
return str(full_name)
def __cmp__(self, other):
if self.name > other.name:
return 1
elif self.name < other.name:
return -1
return 0
def __repr__(self):
full_name = ('%s-%d-%d') %(self.name,self.pseudonode,self.fragment)
#print 'iside Node full_name: {} \n\n\n ------'.format(full_name)
return str(full_name)
and putting some entries in a list :
nodes = []
node = Node('0000.0000.0001',0,0,100,{})
nodes.append(node)
>>> nodes
[0000.0000.0001-0-0]
node = Node('0000.0000.0001',1,0,100,{})
nodes.append(node)
>>> nodes
[0000.0000.0001-0-0, 0000.0000.0001-1-0]
i'm trying to get the index of a node in list nodes[]
>>> node
0000.0000.0001-1-0
>>> nodes.index(node)
0
0 is not what i was expecting. Not sure why this is happening.
edit
i'm after getting the index of the list where '0000.0000.0001-1-0' is.
The index function, when used on a container, relies on its element's __cmp__ function to return the index of the first element that it thinks is equal to the input-object. You probably know as much, since you implemented it for the node. But what you are expecting is that __cmp__ considers not only the name, but also the pseudonode and the fragment, right?
A straight-forward approach would be to consider them a tuple, which performs a comparison of elements from left to right, until the first inequality was found:
def __cmp__(self, other):
self_tuple = (self.name, self.pseudonode, self.fragment)
other_tuple = (other.name, other.pseudonode, other.fragment)
if self_tuple > other_tuple:
return 1
elif self_tuple < other_tuple:
return -1
return 0
If you want another order, you can use the tuples-ordering to define it.

Passing up information in a recursive function

I'm new to programming, and learning python right now. I am building a system in which every object consists of a singleton elements or binary set (of sets of sets..) containing singleton elements or binary sets, i.e., a recursive structure. Within these objects, I have defined a function that gives me immediate containment, and a recursive function that answers the question whether an element is contained in any of the sets members, recursively. Binary Sets and Singletons are subclasses of the metaclass "syntactic object". Every object has a unique identifier, idx, and every object can in principle occur in multiple places, so we could have a set such as the following, with idx attached to the object as -idx
{{A-0,C-2}-4, {B-1, {C-2, {D-3, {A-0,C-2}-4}-5}-6}-7
class SOMeta(object):
"""Abstract class, never instantiated. Has two subtypes, base case, recursive case"""
def __init__(self, idx: int):
self.idx = idx
def i_contains(self, a):
"""self immediately contains a if a is an element of self"""
if type(self) is Binary:
return a in self.syntactic_object_set
else:
return False
def contains(self, a):
"""self contains a if self immediately contains a, or some daughter of self contains a"""
if type(self) is Binary:
if self.i_contains(a):
return True
else:
to_return = False
for daughter in self.syntactic_object_set:
if type(daughter) is Binary:
to_return = to_return or daughter.contains(a)
return to_return
else:
return False
class Binary(SOMeta):
def __init__(self, the_set: Set[SOMeta], idx: int):
super(Binary, self).__init__(idx)
self.syntactic_object_set: Set[SOMeta] = the_set
def __str__(self):
set_strings = {str(obj) for obj in self.syntactic_object_set}
rep = "< " + str(self.idx) + ": " + ", ".join(set_strings) + " >"
return rep
class Singleton(SOMeta):
def __init__(self, lexical_item: string, idx: int):
super(Singleton, self).__init__(idx)
self.lexical_item = lexical_item
def __str__(self):
rep = "< " + str(self.idx) + ": " + str(self.lexical_item) + " >"
return rep
Now, based on this, I am trying to define a function that returns a set of "paths" of an object within an object, starting at the top, where a path is defined as follows:
a path is a sequence of objects < O_1, O_2,..., O_n > where for all 0 < i < n, O_{i+1} is in O_i.
So, for example, if the set in question is {A-0, {B-1,A-0}-2}-3, I want this function to return the following set of lists:
{[{A-0, {B-1,A-0}-2}-3, A-0], [{A-0, {B-1,A-0}-2}-3, {B-1,A-0}-2, A-0]}
I have tried the following recursive function, which works well in the base cases, and the above case, but seems to run into trouble with larger sets. I suspect that I'm doing something wrong in the way that I try to pass up path_set in the function?
def paths(self, so):
"""
:return: all paths to self starting at so
"""
def paths_recursive(self, other, path, path_set = set()):
""" Helper Function """
for x in so.syntactic_object_set:
if x.idx == self.idx:
path += [self]
path_set.update([tuple(path)])
elif type(x) != Singleton:
if x.contains(self):
path1 = path.copy() # Need to make a copy in case both daughters contain self
path1 += [x]
path_set.update(paths_recursive(self, x, path1, path_set))
return path_set
if so.contains(self) == False:
return {}
elif so.idx == self.idx:
return {self}
else:
return paths_recursive(self, so, list([so]))

Python Printing a Deque

I have an entire Deque Array class that looks like this:
from collections import deque
import ctypes
class dequeArray:
DEFAULT_CAPACITY = 10 #moderate capacity for all new queues
def __init__(self):
self.capacity = 5
capacity = self.capacity
self._data = self._make_array(self.capacity)
self._size = 0
self._front = 0
def __len__(self):
return self._size
def __getitem__(self, k): #Return element at index k
if not 0 <= k < self._size:
raise IndexError('invalid index')
return self._data[k]
def isEmpty(self):
if self._data == 0:
return False
else:
return True
def append(self, item): #add an element to the back of the queue
if self._size == self.capacity:
self._data.pop(0)
else:
avail = (self._front + self._size) % len(self._data)
self._data[avail] = item
self._size += 1
#def _resize(self, c):
#B = self._make_array(c)
#for k in range(self._size):
#B[k] = self._A[k]
#self._data = B
#self.capacity = capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
def removeFirst(self):
if self._size == self.capacity:
self._data.pop(0)
else:
answer = self._data[self._front]
self._data[self._front] = None
self._front = (self._front + 1) % len(self._data)
self._size -= 1
print(answer)
def removeLast(self):
return self._data.popleft()
def __str__(self):
return str(self._data)
and when I try to print the deque in the main it prints out something like this,
<bound method dequeArray.__str__ of <__main__.dequeArray object at 0x1053aec88>>
when it should be printing the entire array. I think i need to use the str function and i tried adding
def __str__(self):
return str(self._data)
and that failed to give me the output. I also tried just
def __str__(self):
return str(d)
d being the deque array but I still am not having any success. How do I do i get it to print correctly?
you should call the str function of each element of the array that is not NULL, can be done with the following str function:
def __str__(self):
contents = ", ".join(map(str, self._data[:self._size]))
return "dequeArray[{}]".format(contents)
What I get when I try to q = dequeArray(); print(q) is <__main__.py_object_Array_5 object at 0x006188A0> which makes sense. If you want it list-like, use something like this (print uses __str__ method implicitly):
def __str__(self):
values = []
for i in range(5):
try:
values.append(self._data[i])
except ValueError: # since accessing ctypes array by index
# prior to assignment to this index raises
# the exception
values.append('NULL (never used)')
return repr(values)
Also, several things about the code:
from collections import deque
This import is never user and should be removed.
DEFAULT_CAPACITY = 10
is never used. Consider using it in the __init__:
def __init__(self, capacity=None):
self.capacity = capacity or self.DEFAULT_CAPACITY
This variable inside __init__ is never user and should be removed:
capacity = self.capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
Though this is a valid code, you're doing it wrong unless you're absolutely required to do it in your assignment. Ctypes shouldn't be used like this, Python is a language with automated memory management. Just return [] would be fine. And yes, variable c is never used and should be removed from the signature.
if self._data == 0
In isEmpty always evaluates to False because you're comparing ctypes object with zero, and ctypes object is definitely not a zero.

Obtaining values from dictionary in OOP: "AttributeError"

I am trying to get values from my dictionary VALUES. My program creates combination of possible positions and gets the last position. Then I want to get the value. Everything works well here except indicated .get_value method. When I execute this code I receive:
AttributeError: 'Combination' object has no attribute 'get_value'
Theoretically it should be easy but I am new to OOP and I don't see what is wrong here.
X = ['A','B','C']
Y = ['1','2','3']
VALUES = {'A':10, 'B': 50, 'C':-20}
class Combination:
def __init__(self,x,y):
if (x in X) and (y in Y):
self.x = x
self.y = y
else:
print "WRONG!!"
def __repr__ (self):
return self.x+self.y
def get_x(self):
return self.x
def get_y(self):
return self.y
class Position:
def __init__(self):
self.xy = []
for i in X:
for j in Y:
self.xy.append(Combination(i,j))
def choose_last(self):
return self.xy.pop()
def __str__(self):
return "List contains: " + str(self.xy)
class Operation1:
def __init__(self):
self.operation1 = []
def __str__(self):
s = str(self.operation1)
return s
def get_value(self):
V = VALUES.get(self)
return V
pos = Position()
print pos
last_item = pos.choose_last()
print "Last item:", last_item, pos
last_value = last_item.get_value() # <---- Here is a problem
How can I obtain value of my position? Value is determined by the X value - this is A,B or C. In the dictionary I have a numeral value for the letter.
You are appending objects of Combination into xy of Position. When you say choose_last, it will return the last Combination object inserted into xy. And you are trying to invoke get_value method on a Combination object, which doesnt have that method. Thats why you are getting that error.
Always use new style classes.

Categories