'Python Set not Detecting Duplicate Node
I have created a Graph class along with a Node class that I've tested. It is working with basic tests. I'm now trying to test with a custom input file and I'm running into an error where some of the Nodes are being duplicated. In the Graph class, there is a set called Nodes where the Node being created is added. However, in my parser file I have a checker which checks to see if the Node with the value has been added before but it's not working properly.
Even after adding in the hash function below, I still get set([Alpha, Beta, Hotel, Alpha]).
What am I doing wrong?
Test File:
directed unweighted
Alpha=Hotel
Alpha=Beta
Beta=Charlie
Charlie=Juliett
Charlie=Juliett
Delta=Foxtrot
Delta=Golf
Echo=Charlie
Echo=Delta
Foxtrot=Golf
Golf=Juliett
Golf=Alpha
Hotel=Echo
Hotel=India
India=Beta
India=Golf
Juliett=Golf
Graph and Node Class:
class Graph:
def __init__(self):
self.Nodes = set()
def addVertex(self, vertex):
self.Nodes.add(vertex)
def getVertices(self):
return self.Nodes
@staticmethod
def addEdgeDirect(fromEdge, toEdge, cost=1):
fromEdge.neighbors[toEdge] = cost
class Node():
def __init__(self, val = None):
self.value = val
self.neighbors = {}
def getEdges(self):
return self.neighbors.keys()
def __repr__(self):
return str(self.value)
Test File Parser:
from graph import Graph, Node
graph = Graph()
file1 = open('Graphs/du.gl', 'r')
Lines = file1.readlines()
direction = Lines[0].split(" ")[0].strip()
weight = Lines[0].split(" ")[1].strip()
count = 0
if(direction == "directed"):
if(weight == "unweighted"):
for line in Lines:
count += 1
if(count == 1):
continue
node1 = Node(line.split("=")[0].strip())
node2 = Node(line.split("=")[1].strip())
if node1 not in graph.Nodes:
print("not found, to be added")
graph.addVertex(Node(node1))
if node2 not in graph.Nodes:
graph.addVertex(Node(node2))
print(graph.getVertices())
graph.addEdgeDirect(node1,node2)
# print("Line{}: {}".format(count, line.strip()))
Solution 1:[1]
You are expecting that the set should contain nodes with unique names, but nowhere do you specify that uniqueness should depend on the property value of those nodes.
You should add the following method to your node class:
def __hash__(self):
return hash(self.value)
Solution 2:[2]
There's a few issues, some related to a lack of type checking and some from the design of your class.
First, you have a Node class, instances of which you've kind of implied maybe should have a unique self.value, and that self.value is expected to always be a string (although these expectations are not contained in the code).
One problem causing the set() behavior, addressed in another comment, is the lack of a __hash__() method. Since it seems like you maybe want two Nodes to be equal if and only if their value parameter is the same string, adding
def __hash__(self):
return hash(self.value)
is needed. However, for set() to work like you want, you also need to add an __eq__() function.
def __eq__(self, other):
return isinstance(other, Node) and self.value == other.value
It's unclear to me whether the 'neighbors' attribute of a node should matter for its identity, as the terms node and graph don't carry information about what the classes actually are or represent, so maybe neighbors should be included in __eq__ too.
After adding those methods, the body of your loop is still incorrect. The problem line is graph.addVertex(Node(node1)) specifically the Node(node1). Supposedly that was intended to create a copy of node1, but it actually initializes a new node, where newnode.value is now an instance of Node, not a string. Using type hints and/or explicit type checking helps catch those problems, for example, adding a check for isinstance(value, str) to the initialization body.
Replacing those two conditionals from the loop body, the correct version would be:
if node1 not in graph.Nodes:
graph.addVertex(node1)
if node2 not in graph.Nodes:
graph.addVertex(node2)
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 | Jonathan H |
| Solution 2 | kcsquared |
