So I am implementing BFS on a Graph to detect all the cycles. I implemented the graph via an adjacency list. But when I run my code I get the following error
Traceback (most recent call last):
File "C:\Python27\Data Structures\Graph\bfstree.py", line 228, in <module>
main()
File "C:\Python27\Data Structures\Graph\bfstree.py", line 223, in main
traverse(g.getVertex(2))
File "C:\Python27\Data Structures\Graph\bfstree.py", line 168, in traverse
while (x.getPred()):
AttributeError: 'list' object has no attribute 'getPred'
So the problem occurs when I call the traverse() function.
Here is my main function
def main():
g = Graph()
for i in range(1,9):
g.addVertex(i)
g.addEdge(1,2)
g.addEdge(1,4)
g.addEdge(1,8)
g.addEdge(2,3)
g.addEdge(2,1)
g.addEdge(3,2)
g.addEdge(3,4)
g.addEdge(3,7)
g.addEdge(3,8)
g.addEdge(4,1)
g.addEdge(4,3)
g.addEdge(4,5)
g.addEdge(5,4)
g.addEdge(5,6)
g.addEdge(5,7)
g.addEdge(6,5)
g.addEdge(6,7)
g.addEdge(7,3)
g.addEdge(7,6)
g.addEdge(7,5)
g.addEdge(8,3)
g.addEdge(8,1)
for v in g:
for w in v.getConnections():
print("(%s,%s)"%(v.getId(),w.getId()))
print("\nDoing BFS...")
bfs_tree(g,g.getVertex(1))
a = g.getVertex(2)
print(type(a))
traverse(g.getVertex(2))
main()
Here is the traverse function:
def traverse(y):
x = y
while (x.getPred()):
print(x.getId())
x = x.getPred()
print(x.getId())
Here is the adjacency list implementation of the graph:
class Graph:
def __init__(self):
self.vertList = {} #this is the masterlist
self.numVertices = 0
def addVertex(self,key): #turn something into a Vertex object
self.numVertices = self.numVertices + 1
newVertex = Vertex(key)
self.vertList[key] = newVertex #maps vertex names to vertex objects
return newVertex
def getVertex(self,n):
if n in self.vertList:
return self.vertList[n] #returns the Vertex object
else:
return None
def __contains__(self,n):#tweak the built-in operator 'in'(containment check)
return n in self.vertList
def addEdge(self,f,t,cost = 0):
if f not in self.vertList: #if f is not a node in the graph
nv = self.addVertex(f)
if t not in self.vertList: #if t is not a node in the graph
nv = self.addVertex(t)
self.vertList[f].addNeighbor(self.vertList[t], cost)
def getVertices(self):
return self.vertList.keys()
def __iter__(self): # iterate over Vertex objects over the Graph
return iter(self.vertList.values())
class Vertex:
def __init__(self,key):
self.id = key
self.connectedTo={} #dictionary which contains all the other vertices it is connected to
self.pred = [] #for BFS tree / a list because we are dealing with cycles
self.color = "white" #for BFS tree
def addNeighbor(self,nbr,weight=0):
self.connectedTo[nbr] = weight #nbr is another Vertex object
def __str__(self):
#TODO: lookup how that for loop works
return str(self.id) + "connected to " + str([x.id for x in self.connectedTo])
def getConnections(self):
return self.connectedTo.keys()
def getId(self):
return self.id
def getWeight(self,nbr):
return self.connectedTo[nbr]
def getColor(self):
return self.color
def setColor(self,color):
self.color = color
def setPred(self,node):
self.pred.append(node)
def getPred(self):
if len(self.pred)>1:
return self.pred
elif len(self.pred) == 0:
return self.pred[0]
else:
return self.pred
Why is it saying that g.getVertex(2) is a list object? I am pretty sure that it's a Vertex object. I even printed out the type in the main function and it says it's an instance and not a list object.
You replace x with the result of x.getPred() here:
while (x.getPred()):
print(x.getId())
x = x.getPred()
x.getPred() returns self.pred:
def getPred(self):
if len(self.pred)>1:
return self.pred
elif len(self.pred) == 0:
return self.pred[0]
else:
return self.pred
(Note that for len(self.pred) == 0 you try to return self.pred[0], which will raise an IndexError exception).
self.pred is a list:
class Vertex:
def __init__(self,key):
# ...
self.pred = [] #for BFS tree / a list because we are dealing with cycles
So you replaced x with a list object, then loop back and call x.getPred() on that list object.
x = x.getPred() is the problem. The first check in the while loop is fine, but it breaks after x is updated the first time, then rechecked.
As implemented, getPred is returning self.pred (the only case where it returns a value from self.pred instead of the whole thing is broken; the length is 0, and you index, so it will raise IndexError). self.pred is a list.
Related
Update
Thanks to the comments of some community members, I realize that there are some similar problems, but they may a bit different, please allow me to explain it further.
I actually hope to use the same method in a real problem, So briefly:
Reuse of edges in differernt path is completely allowed
a unique(or a new) path from A to B is defined as a collection of vertices that have any different vertices.
Let me use a quiz from Python data structure and algorithm analysis by Bradley .N Miller and David L. Ranum to expain my qusetion.
Quesion:
Consider the task of converting the word FOOL to SAGE, also called word ladder problem. In solving
In the word ladder problem, only one letter must be replaced at a time, and the result of each step must be a word, not non-existent.
Input:
FOUL
FOOL
FOIL
FAIL
COOL
FALL
POOL
PALL
POLL
POLE
PALE
PAGE
SALE
POPE
POPE
SAGE
We can easily find the path from FOOL to SAGE, as Bradley showed:
enter image description here
and I used Breadth First Search (BFS) to solve probem:
class Vertex:
def __init__(self, key, value = None):
self.id = key
self.connectedTo = {}
self.color = 'white'
self.dist = sys.maxsize
self.pred = []
self.disc = 0
self.fin = 0
self.value = value,
#self.GraphBulided = False
self.traverseIndex = 0
self.predNum = 0
def addNeighbor(self, nbr, weight=0):
self.connectedTo[nbr] = weight
def __str__(self):
return '{} connectedTo: {}'.format(self.id, \
str([x.id for x in self.connectedTo]))
def setColor(self, color):
self.color = color
def setDistance(self, d):
self.dist = d
#I want store all Pred for next traverse so I use a list to do it
def setPred(self, p, list = False):
if not list:
self.pred = p
else:
self.pred.append(p)
self.predNum += 1
def setDiscovery(self,dtime):
self.disc = dtime
def setFinish(self,ftime):
self.fin = ftime
#def setGraphBulided(self, tag = True):
# self.GraphBulided = tag
def getFinish(self):
return self.fin
def getDiscovery(self):
return self.disc
def getPred(self):
if isinstance(self.pred, list):
if self.traverseIndex < self.predNum:
return self.pred[self.traverseIndex]
else:
return self.pred[-1]
else:
return self.pred
def __hash__(self):
return hash(self.id)
def getPredById(self):
if self.traverseIndex < self.predNum and isinstance(self.pred, list):
pred = self.pred[self.traverseIndex]
self.traverseIndex += 1
print("vertix {}: {} of {} preds".format(self.id, self.traverseIndex, self.predNum))
return [pred, self.traverseIndex]
else:
pred = None
return [pred, None]
def getCurrPredStaus(self):
#if not self.pred:
# return None
return self.predNum - self.traverseIndex
def getDistance(self):
return self.dist
def getColor(self):
return self.color
def getConnections(self):
return self.connectedTo.keys()
def getId(self):
return self.id
def getWeight(self, nbr):
return self.connectedTo[nbr]
def getValue(self):
return self.value
def findPath(self, dest):
pass
class Graph:
def __init__(self):
self.vertList = {}
self.numVertics = 0
self.verticsInSerach = set()
self.GraphBulided = False
def addVertex(self, key, value = None):
self.numVertics = self.numVertics + 1
newVertex = Vertex(key, value=value)
self.vertList[key] = newVertex
return newVertex
def getVertex(self, n):
if n in self.vertList:
return self.vertList[n]
else:
return None
def __contains__(self, n):
return n in self.vertList
def addEdge(self, f, t, cost = 0, fvalue = None, tvalue = None):
if f not in self.vertList:
nv = self.addVertex(f, fvalue)
if t not in self.vertList:
nv = self.addVertex(t, tvalue)
self.vertList[f].addNeighbor(self.vertList[t], cost)
def setGraphBulided(self, tag = True):
self.GraphBulided = tag
def getVertices(self):
return self.vertList.keys()
def setGraphBulided(self, tag = True):
self.GraphBulided = tag
def setSerachedVertixs(self, vertix):
self.verticsInSerach.add(vertix)
def getGraphBulided(self):
return self.GraphBulided
def getSerachedVertixs(self):
return self.verticsInSerach
def __iter__(self):
return iter(self.vertList.values())
def __hash__(self):
hashIds = [x for x in self.getVertices()]
if len(hashIds) > 0 and hashIds[0]:
return hash(', '.join(hashIds))
else:
return None
Here are some additional functions for building graphs
def buildGraph(wordFile, DFSgraph = False):
d = {}
g = Graph()
if DFSgraph:
g = DFSGraph()
wfile = open(wordFile)
for line in wfile:
word = line[:-1]
for i in range(len(word)):
bucket = word[:i] + '_' + word[i+1:]
if bucket in d:
d[bucket].append(word)
else:
d[bucket] = [word]
for bucket in d.keys():
for word1 in d[bucket]:
for word2 in d[bucket]:
if word1 != word2:
g.addEdge(word1, word2)
wfile.close()
return g
class Queue:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def enqueue(self, item):
self.items.insert(0,item)
def dequeue(self):
return self.items.pop()
def size(self):
return len(self.items)
def bfs(g, start, listpred = False):
start.setDistance(0)
start.setPred(None)
vertQueue = Queue()
vertQueue.enqueue(start)
while (vertQueue.size() > 0):
currentVert = vertQueue.dequeue()
if currentVert.getConnections():
g.setSerachedVertixs(currentVert)
for nbr in currentVert.getConnections():
#print('sreach {}'.format(currentVert.getId()))
if (nbr.getColor() == 'white' or nbr.getColor() == 'gray'):
nbr.setColor('gray')
nbr.setDistance(currentVert.getDistance() + 1)
if nbr.predNum > 0 and currentVert.getId() not in [x.getId() for x in nbr.pred]:
nbr.setPred(currentVert, listpred)
elif nbr.predNum == 0:
nbr.setPred(currentVert, listpred)
vertQueue.enqueue(nbr)
currentVert.setColor('black')
Therefore, we can easily find the shortest path we need (If we only store one pred for one vertix).
wordGraph = buildGraph('fourletterwords1.txt', DFSgraph=False)
bfs(wordGraph, wordGraph.getVertex('FOOL'), listpred=True)
def traverse(y):
x=y
while(x.getPred()):
print(x.getPred())
x = x.getPred()
print(x.getId())
traverse(wordGraph.getVertex('SAGE'))
However, I still don't know how to trace all the paths correctly, can you give me some suggestions?
FIND path from src to dst ( Dijkstra algorithm )
ADD path to list of paths
LOOP P over list of paths
LOOP V over vertices in P
IF V == src OR V == dst
CONTINUE to next V
COPY graph to working graph
REMOVE V from working graph
FIND path from src to dst in working graph( Dijkstra algorithm )
IF path found
IF path not in list of paths
ADD path to list of paths
I have a problem with an algorithmic task. There is content of it: "You have ten points on a plane and none three of them are collinear, each pair of different points is connected by line segment, which is green or blue. Calculate how many triangles have sides only in one colour." I tried a solution with n-ary trees but I get repeated triangles with cyclic permutations of integers on the result list.
Patryk, the problem is solvable with n-trees. However, to avoid cyclic permutations you need to skip symmetric line segments. If you create a line segment from 0 -> 1 you do not need to create a segment from 1 -> 0. Below is a complete code which solves the problem with n-trees with the recursive depth-first search. Excuse for Polish names of classes and methods. The interface is in English however. If you analyze the code you will get the point surely.
from random import choice
import copy
class Punkt:
def __init__(self, numer):
self.__numer = numer
self.__odcinki = {}
def dodaj_odcinek_wychodzący(self, punkt_docelowy, kolor):
self.__odcinki[punkt_docelowy] = Odcinek(self.__numer, punkt_docelowy, kolor)
def wez_odcinek_do_punktu_docelowego(self, punkt_docelowy):
return (punkt_docelowy, self.__odcinki[punkt_docelowy].wez_kolor())
def liczba_odcinkow(self):
return len(self.__odcinki)
def wez_kolor_punktu_docelowego(self, punkt_docelowy):
return self.__odcinki[punkt_docelowy].wez_kolor()
def lista_punktow_docelowych(self):
return self.__odcinki.keys()
class Odcinek:
def __init__(self, punkt_zrodlowy, punkt_docelowy, kolor):
self.__punkt_zrodlowy = punkt_zrodlowy
self.__punkt_docelowy = punkt_docelowy
self.__kolor = kolor
def wez_kolor(self):
return self.__kolor
class Structure:
def __init__(self, liczba_punktow=10):
self.__punkty = [Punkt(i)
for i in range(liczba_punktow)]
for i in range(liczba_punktow):
for j in range(i + 1, liczba_punktow):
self.__punkty[i].dodaj_odcinek_wychodzący(j, choice(["green", "blue"]))
# for j in range(liczba_punktow):
# for i in range (j + 1, liczba_punktow):
# self.__punkty[j].dodaj_odcinek_wychodzący(*(self.__punkty[j].wez_odcinek_do_punktu_docelowego(i)))
def wez_punkt(self, numer):
return self.__punkty[numer]
def wez_liczbe_punktow(self):
return len(self.__punkty)
class Search:
def __init__(self, struktura):
self.__s = struktura
def wez_liczbe_punktow(self):
return self.__s.wez_liczbe_punktow()
def wez_punkt(self, numer):
return self.__s.wez_punkt(numer)
def szukaj(self, kolor="green"):
self.__szukany_kolor = kolor
lista_trojkatow = []
liczba_trojkatow = 0
wszystkie_trojkaty = []
for i in range(self.wez_liczbe_punktow()):
lista_odwiedzonych_punktow = [i]
lista_trojkatow = self.szukaj_z_punktu(i,lista_odwiedzonych_punktow,lista_trojkatow)
return len(lista_trojkatow), lista_trojkatow
def wez_szukany_kolor(self):
return self.__szukany_kolor
def szukaj_z_punktu(self, numer, trojkat, lista_trojkatow):
if len(trojkat) == 3: # jeżeli zebraliśmy już trzy punkty to brakuje tylko zamykającego, czwartego
if self.wez_punkt(trojkat[0]).wez_kolor_punktu_docelowego(
trojkat[-1]) == self.wez_szukany_kolor(): # sprawdź czy do punktu zamykającego prowadzi odcinek o szukanym kolorze
trojkat.append(trojkat[0]) # dodaj punkt zamykajacy do trójkąta
lista_trojkatow.append(trojkat) # dodaj trojkąt do listy trójkątów
# return lista_trojkatow # zwróć liste trójkątów obliczonych dotychczas
else:
potomkowie = []
for punkt_docelowy in self.wez_punkt(numer).lista_punktow_docelowych():
if self.wez_punkt(numer).wez_kolor_punktu_docelowego(punkt_docelowy) == self.wez_szukany_kolor():
potomkowie.append(punkt_docelowy)
for potomek in potomkowie:
trojkat_kopia = copy.copy(trojkat)
trojkat_kopia.append(potomek)
lista_trojkatow = self.szukaj_z_punktu(potomek, trojkat_kopia, lista_trojkatow)
return lista_trojkatow
if __name__ == "__main__":
s = Structure()
for source_point in range(s.wez_liczbe_punktow()):
for destination_point in s.wez_punkt(source_point).lista_punktow_docelowych():
print(f"{source_point} -> {destination_point} = {s.wez_punkt(source_point).wez_kolor_punktu_docelowego(destination_point)}")
color = "green"
searching = Search(s)
number_of_triangles, all_triangles = searching.szukaj("green")
print(f"Number of triangles of color {color} = {number_of_triangles}")
print(f"List of all triangles: {all_triangles}")
need a help with Dijkstra. I found a lot of codes on the internet, but I can't use any of them, because I'm not given a graph, but just lists of Vertexes & Edges into createGraph function. It's a homework and I gotta have some attributes in classes.
This is what I have:
class Vertex:
def __init__(self, id, name):
self.id = id
self.name = name
self.minDistance = float('inf')
self.previousVertex = None
self.edges = []
self.visited = False
class Edge:
def __init__(self, source, target, weight):
self.source = source
self.target = target
self.weight = weight
class Dijkstra:
def __init__(self):
self.vertexes = []
self.result = 0
def createGraph(self, vertexes, edgesToVertexes):
for i in range(len(vertexes)):
self.vertexes.append(vertexes[i])
for j in range(len(edgesToVertexes)):
if edgesToVertexes[j].source == vertexes[i].id:
vertexes[i].edges.append(edgesToVertexes[j])
def getVertexes(self):
return self.vertexes
def findMinID(self):
maxDistance = 1000000
curVertex = None
result = None
for i in range(len(self.vertexes)):
self.vertexes[i] = curVertex
if curVertex.visited is False and curVertex.minDistance < maxDistance:
curVertex = result
curVertex.minDistance = maxDistance
else:
pass
self.result = result
return
def computePath(self, sourceId):
start = None
end = None
road = None
while start is None:
if Vertex.id == sourceId:
start = Vertex
start.minDistance = 0
start.visited = True
for i in range(len(start.edges)):
start.edges[i].target = end
start.edges[i].weight = road
if road < end.minDistance:
end.minDistance = start.minDistance + road
end.previousVertex = start.id
else:
pass
self.findMinID()
self.computePath(self.result.id)
I'm still beginner so I tried to keep it simple, but it's not working as it raises error:
'type' object is not subscriptable
or:
AttributeError: type object 'Vertex' has no attribute 'id'
which makes absolutely no sense to me why.
I can use any help, thanks in advance!
When you put the line:
self.vertexes = Vertex
you are assigning the variable to the actual class. Probably what you wanted to do was make an empty list, as you append to it later:
self.vertexes = []
I would assume this is where the error comes from, as if you ever try to iterate over self.vertexes, you are iterating over the Vertex class, which is impossible and throws that error.
You also have later:
start = Vertex
Try initializing the start, like:
start = Vertex(sourceId, "vertex")
Also, the line before that you have
if Vertex.id == sourceId:
meaning that you might want to make the id variable in Vertex static:
class Vertex:
id = 0
def __init__(self, id, name):
self.id = id
id += 1
Some suggestions: class tutorial in python
Edit:
To find the vertex that has the id you want, use a filter:
start = None
for v in self.vertexes:
if v.id == sourceId:
start = Vertex(sourceId, v.name)
start.minDistance = 0
break
I'm trying to make an undirected graph from an adjacency list to practice the Karger's Min Cut algorithm. The following is my code
class Vertex(object):
'''Represents a vertex, with the indices of edges
incident on it'''
def __init__(self,name,edgeIndices=[]):
self.name = name
self.edgeIndices = edgeIndices
def getName(self):
return self.name
def addEdge(self,ind):
self.edgeIndices.append(ind)
def getEdges(self):
return self.edgeIndices
def __eq__(self,other):
return self.name == other.name
class Edge(object):
'''Represents an edge with the indices of its endpoints'''
def __init__(self,ends):
self.ends = ends
def getEnds(self):
return self.ends
def __eq__(self,other):
return (self.ends == other.ends)\
or ((self.ends[1],self.ends[0]) == other.ends)
class Graph(object):
def __init__(self,vertices,edges):
self.edges = edges
self.vertices = vertices
def createGraph(filename):
'''Input: Adjacency list
Output: Graph object'''
vertices = []
edges = []
with open(filename) as f:
for line in f:
elements = line.split()
newVert = Vertex(elements[0])
if newVert not in vertices:
vertices.append(newVert)
for verts in elements[1:]:
otherVert = Vertex(verts)
if otherVert not in vertices:
vertices.append(otherVert)
end1 = vertices.index(newVert)
end2 = vertices.index(otherVert)
newEdge = Edge((end1,end2))
if newEdge not in edges:
edges.append(newEdge)
newVert.addEdge(edges.index(newEdge))
return Graph(vertices,edges)
Suppose the adjacency list is as follows with vertices represented by integers
1 -> 2,3,4
2 -> 1,3
3 -> 1,2,4
4 -> 1,3
In total, this graph will have five edges, so the length of list holding indices of edges a vertex is associated with can't more than 5 long.
For instance, I expect the vertex '2' to have indices of just two edges, i.e. edges with vertices 1 and 3. Instead, what I get is [0, 1, 2, 3, 0, 2, 1, 3].
I need help to figure out what is going wrong.
First error comes from the Vertex init. When passing a list as default argument, Python instantiates it once, and share this instance with all future instances of Vertex.
Pass None, and use a local list if no list is given.
class Vertex(object):
def __init__(self,name,edgeIndices=None):
self.name = name
self.edgeIndices = edgeIndices if edgeIndices else []
In the createGraph method, when the vertex already exists in the graph you need to use it. See the added else: newVert = ...
You also seem to have an issue with the ligne splitting. See the iteration over elements[2].split(',').
def createGraph(filename):
'''Input: Adjacency list
Output: Graph object'''
vertices = []
edges = []
with open(filename) as f:
for line in f:
elements = line.split()
newVert = Vertex(elements[0])
if newVert not in vertices:
vertices.append(newVert)
else:
newVert = vertices[vertices.index(newVert)]
for verts in elements[2].split(','):
otherVert = Vertex(verts)
if otherVert not in vertices:
vertices.append(otherVert)
end1 = vertices.index(newVert)
end2 = vertices.index(otherVert)
newEdge = Edge((end1,end2))
if newEdge not in edges:
edges.append(newEdge)
newVert.addEdge(edges.index(newEdge))
return Graph(vertices,edges)
As a side note, I would try to use a dict to store the vertices (and edges) and do the lookup. List.index is used a lot, and you may create a lot of objects for nothing.
I would recommend to take a look at Dict, OrderedDict, Linked List based graph implementations. The are far more effective then based on lists and indexes.
To make you code work you can do the following:
Change a Vertex to avoid issue described in previous answer:
class Vertex(object):
def __init__(self,name, edgeIndices=None):
self.name = name
self.edgeIndices = edgeIndices or []
Let the graph do some work:
class Graph(object):
def __init__(self):
self.edges = []
self.vertices = []
def add_vertex(self, name):
vertex = Vertex(name)
if vertex not in self.vertices:
self.vertices.append(vertex)
def add_edge(self, *names):
self._add_vertices(names)
edge = self._add_edge(names)
self._update_vertices_links(edge, names)
def get_vertex_index(self, name):
vertex = Vertex(name)
return self.vertices.index(vertex)
def get_vertex(self, name):
return self.vertices[self.get_vertex_index(name)]
def _update_vertices_links(self, edge, names):
for name in names:
vertex = self.get_vertex(name)
vertex.addEdge(self.edges.index(edge))
def _add_edge(self, names):
edge = Edge((self.get_vertex_index(names[0]), self.get_vertex_index(names[1])))
if edge not in self.edges:
self.edges.append(edge)
return edge
def _add_vertices(self, names):
for name in names:
self.add_vertex(name)
def __repr__(self):
return "Vertices: %s\nEdges: %s" % (self.vertices, self.edges)
Create Graph:
def createGraph(filename):
with open(filename) as f:
graph = Graph()
for line in f:
elements = line.strip().split()
graph.add_vertex(elements[0])
for element in elements[2].split(","):
graph.add_edge(elements[0], element)
return graph
Run it:
graph = createGraph('input.txt')
print graph
Output for your input:
Vertices: [<Name:1 Edges:[0, 1, 2]>, <Name:2 Edges:[0, 3]>, <Name:3 Edges:[1, 3, 4]>, <Name:4 Edges:[2, 4]>]
Edges: [(0, 1), (0, 2), (0, 3), (1, 2), (2, 3)]
Trying to write a function that will iterate over the linked list, sum up all of the odd numbers and then display the sum. Here is what I have so far:
def main():
array = eval(input("Give me an array of numbers: "))
ArrayToList(array)
print(array[0])
print(array[1])
print(array[2])
print(array[3])
print(sumOdds(array))
def isOdd(x):
return x % 2 != 0
def sumOdds(array):
if (array == None):
return 0
elif (isOdd(head(array))):
return head(array) + sumOdds(tail(array))
else:
return sumOdds(tail(array))
main()
I can't get it to actually print the sum though. Can anybody help me out with that?
Here is the output of the program when I run it:
$ python3 1.py
Give me an array of numbers: [11, 5, 3, 51]
Traceback (most recent call last):
File "1.py", line 22, in <module>
main()
File "1.py", line 10, in main
print(sumOdds(array))
File "1.py", line 19, in sumOdds
return head(array) + sumOdds(tail(array))
File "1.py", line 18, in sumOdds
elif (isOdd(head(array))):
File "/Users/~/cs150/practice3/friday/List.py", line 34, in head
return NodeValue(items)
File "/Users/~/cs150/practice3/friday/List.py", line 12, in NodeValue
def NodeValue(n): return n[0]
TypeError: 'int' object is not subscriptable
I'd suggest NOT using eval, for starters.
If you just want input from the console just go for raw_input and prompt the user to enter commas or some other delimiting character.
number_string = raw_input("Give me a string of numbers separated by commas, plz.")
Once you have this you can use list comprehension to glean the actual list from the data. int() is pretty good about ignoring whitespace. Maybe this is what yourArrayToList() does, but this works as well.
number_list = [int(x) for x in number_string.split(",")]
Also, if you want to simply iterate over the list and print the received values, might I suggest a for loop instead of just hard-coding the first four items?
for num in number_list:
print num
Additionally, the if (array == None) is a bit less pythonic than if not array:, and really the sum() function is smart enough to just return 0 if the list has no length anyway.
def sum_the_odds(yourlist):
return sum([x for x in yourlist if x % 2 == 1])
So to put it in context:
def sum_the_odds(yourlist):
return sum([x for x in yourlist if x % 2 == 1])
def main():
number_string = raw_input("Give me a string of numbers separated by commas, plz.")
number_list = [int(x) for x in number_string.split(",")]
for num in number_list:
print num
print sum_the_odds(number_list)
I would just implement a filter/reduce function from within the list and just pass a function into the filter_reduce(func) function to accumulate the sum of the filtered items.
You can check out the live demo here: Python Fiddle
def calc_product(a, b):
return a * b
def calc_summation(a, b):
return a + b
def is_odd(x):
return x % 2 != 0
l = linked_list()
l.insert_end(1)
l.insert_end(2)
l.insert_end(3)
l.insert_end(5)
l.insert_beginning(0)
l.insert_after(4, 3)
print 'List:', l
print 'Size:', l.size()
# Calculates the sum of all odd values in the list:
print 'Summation:', l.filter_reduce(calc_summation, is_odd)
# Calculates the product of all values with the accumulator
# initialized at 10.
print 'Product:', l.filter_reduce(calc_product, lambda x: True, 10)
Output
List: 0, 1, 2, 3, 4, 5
Size: 6
Summation: 9
Product: 1200
linked_list.py
class linked_list():
class node():
def __init__(self, data=None):
self.data = data
self.next = None
def __str__(self):
return str(data)
class list_iterator():
def __init__(self, current_node=None):
self.current_node = current_node
def hasNext(self):
return self.current_node.next is not None
def next(self):
if not self.hasNext():
return None
self.current_node = self.current_node.next;
return self.current_node.data;
def __init__(self):
self.head = None
self._size = 0
def iterator(self):
return self.list_iterator(self.head)
def is_empty(self):
return self.head is None
def size(self):
return self._size
def insert_after(self, data, index):
new_node = self.node(data)
curr_node = self.head
i = 0
while curr_node is not None and i < index:
curr_node = curr_node.next
i += 1
new_node.next = curr_node.next
curr_node.next = new_node
self._size += 1
def insert_beginning(self, data):
new_node = self.node(data)
if self.is_empty():
self.head = new_node
else:
new_node.next = self.head
self.head = new_node
self._size += 1
def insert_end(self, data):
new_node = self.node(data)
if self.is_empty():
self.head = new_node
else:
curr_node = self.head
while curr_node.next is not None:
curr_node = curr_node.next
curr_node.next = new_node
self._size += 1
def filter_reduce(self, reduce_func, filter_func=None, initializer=None):
it = self.iterator()
if initializer is None:
try:
initializer = it.next()
except StopIteration:
raise TypeError('reduce() of empty sequence with no initial value')
accum_value = initializer
while it.hasNext():
data = it.next()
if filter_func is None or filter_func(data):
accum_value = reduce_func(accum_value, data)
return accum_value
def __str__(self):
s, it = '', self.iterator()
while it.hasNext():
s += str(it.next())
if it.hasNext():
s += ', '
return s
Your line ArrayToList(array) is suspicious. Because I don't know what it is suppose to do. I suspect it is suppose to convert your python list into a customly defined version of a list. If this is the case, I'm guessing it has a return value. So try changing your main function to do this:
def main():
user_input = eval(input("Give me an array of numbers: "))
custom_list = ArrayToList(user_input) # convert user input to a custom list.
print(sumOdds(custom_list))
You could see if that works for you.
The actual problem you are having is with the tail() function (or your understanding of what tail is suppose to return). As it is, tail is returning an int and you are expecting it to return a list. If you didn't write the tail function, try using just the tail function and observe its output to gain a good understanding of how it should be used. I suggest just running this code and seeing what it does:
def main():
print(tail([1, 2, 3, 4])) # Your code assumes tail returns [2, 3, 4]