Determine if two dictionaries are equal Python error - python

I am creating a doubly linked structure and am having some issues with comparing if two nodes are equal. The structure is fairly complex in that it has multiple attributes including name, row, column, right, left, up, and down. If two nodes are equal they must agree on all of these attributes. I know in my eq method I could simply hard code checking each attribute versus the other but I figured there would be an easier way to do it and found a way that works most of the time. Thus I have the following:
def __init__ (self,row,col,name=None,up=None,down=None,left=None,right=None):
self.name = name
self.row = row
self.col = col
self.up = up
self.down = down
self.left = left
self.right = right
def __eq__ (self, other):
return vars(self) == vars(other)
And various other methods that aren't really important to this. So my shortcut for determining whether two Nodes was to basically look at the dictionary of their variables and let python compare the two dictionaries for equivalence.
This works great! As long as the two nodes are actually equal. It returns True and I go on my merry way with my code. BUT if the two nodes are actually not equal it falls apart. I get
File "*filename*", line 35 in __eq__ return vars(self) == vars(self)
written to the screen numerous amounts of times until it finally says
RuntimeError: maximum recursion depth exceeded
I know there are some ways around this, i.e. I could explicitly check each attribute, but that's lame and I want to know why this isn't working, and if it can be easily fixed. I have tested this method with other simpler dictionaries and it works so my thought is that the issue has something to do with determining if objects are equal but I have no idea what I could do here. I realize I could also just do a error catch and then make that return False but something other than those two solutions would be appreciated,

It looks like your up, down, etc are pointing to other instances of your class.
Your comparison code is basically saying, to test if self == other, does self.up == other.up? does self.up.up == other.up.up? etc. And then recursing until it runs out of space.
You may instead want to use
def __eq__(self, other):
return self.name == other.name \
and self.row == other.row \
and self.col == other.col \
and self.up is other.up \
and self.down is other.down \
and self.left is other.left \
and self.right is other.right

I have no python at hand, but I guess this is what happens:
in the __dict__ of self and in the __dict__ of other is areference to one of your nodes
now this node is compared for equality (once the one from vars, once the one from other), this causes your comparison method to be called.
If you now have a loop (e.g common parent) you get infinite recursion:
in original comparison:
compare self.parent to other.parent
in parent comparison:
compare self.parent.child to other.parent.child
(parent and child refer to your up and down)
try(untested):
def __eq__(self, other):
for s, o in zip(vars(self),vars(other)):
if not s is o and s != o:
return False
return True
basically what Hugh Bothwell suggested, just in a loop. First check if you have the same object in memory, if so don't compare them, otherwise test.

Related

how to sort a list that is contained in an object

The task is to code a sorting algorithm using the below code as a starting point. The issue is I cannot seem to figure out how I go about starting the code, I'm not looking for the full solution - just techniques in how to sort lists of tuples that are actually part of an object. I get errors when I try to iterate through the list, saying cannot iterate through an object.
class LinkedList:
def __init__(self, data):
self.label = data[0][0]
self.value = data[0][1]
self.tail = None if (len(data) == 1) else LinkedList(data[1:])
countries = LinkedList([("Ukraine",41879904),("Brunei",442400),("Christmas Island (Australia)",1928)
You can use a pointer to iterate through linked list.:
curr = countries
while curr:
print("Label {}, Value {}".format(curr.label, curr.value))
curr = curr.tail
In order to sort linked list, firstly, you need to implement helper functions to remove/insert a node to given linked list at certain position. Once you have such methods, you can implement any of the famous sorting algorithms (e.g quick sort) using your helper methods you just created.
To iterate over this list you need to keep getting the tail reference of the object:
class LinkedList:
def __init__(self, data):
self.label = data[0][0]
self.value = data[0][1]
self.tail = None if (len(data) == 1) else LinkedList(data[1:])
countries = LinkedList([("Ukraine",41879904),("Brunei",442400),("Christmas Island (Australia)",1928)])
nextObj = countries
while nextObj is not None:
print(nextObj.label, nextObj.value)
nextObj = nextObj.tail
print("done!")
output:
Ukraine 41879904
Brunei 442400
Christmas Island (Australia) 1928
done!
To get an element at a certain index, you start iterating from the first element and just keep a counter.
functools, #total_ordering
One of the powerful features in python. you can sort objects in a classic and easy straitforward way.
Functools module in python helps in implementing higher-order functions. Higher-order functions are dependent functions that call other functions. Total_ordering provides rich class comparison methods that help in comparing classes without explicitly defining a function for it. So, It helps in the redundancy of code.
There are 2 essential conditions to implement these comparison methods
At least one of the comparison methods must be defined from lt(less than), le(less than or equal to), gt(greater than) or ge(greater than or equal to).
The eq function must also be defined
from functools import total_ordering
#total_ordering
class LinkedList(object):
def __init__(self, data):
self.label = data[0][0]
self.value = data[0][1]
def __lt__(self, other):
return self.label < other.value ##lets assume that the sort is based on label data member(attribute)
def __eq__(self, other):
return self.label == other.value
##I dont know what data is. just pass your data objects to list of LinkedList objects. and sort it with sorted method (treat them like int objects)!
my_list = [LinkedList(data0),LinkedList(data1),LinkedList(data2)]
new_list=my_list.sorted()
for obj in new_list:
print(...)

Techniques used in checking if a binary tree is symmetric

Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
Question link is here
The recursion method need to traverse the tree twice.
But one of the comment provided a solution used a technique called 'Null check'. I can't understand why in this way can we avoid checking the tree twice?
Here is his code in C++:
bool isSymmetric(TreeNode* root) {
if (!root) return true;
return isSymmetric(root->left, root->right);
}
bool isSymmetric(TreeNode* t1, TreeNode* t2){
if (!t1 && !t2) return true;
if (!t1 || !t2) return false;
return t1->val == t2->val
&& isSymmetric(t1->left, t2->right)
&& isSymmetric(t1->right, t2->left);
}
I have also tried to modify it into python3 and my code also passed all test cases!
Here is my code:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root):
return self.helper(root)
def helper(self,root):
if root is None:
return True
#why we can redefine the helper here?
def helper(left,right):
if left is None and right is None:
return True
if left is None or right is None:
return False
return left.val==right.val and helper(left.left,right.right) and helper(left.right,right.left)
return helper(root.left,root.right)
I have never met such kind of recursion before.
(1) Why we can redefine the function helper with different arguments in helper function itself?
(2) My intuition tells me that helper function will stop execution once it returns back to the root thus the tree won't be checked twice. But I don't know why.
A def statement is really just a fancy assignment statement. In Solution.helper, you are defining a local variable named helper that is bound to another function. As a result, all references inside Solution.helper and the local function to the name helper resolve to the local function.
Solution.helper is not a recursive function; only the local function is. You could write the same thing (less confusingly but equivalently) as
class Solution:
def isSymmetric(self, root):
return self.helper(root)
def helper(self,root):
if root is None:
return True
def helper2(left,right):
if left is None and right is None:
return True
if left is None or right is None:
return False
return left.val==right.val and helper2(left.left,right.right) and helper2(left.right,right.left)
return helper2(root.left,root.right)
The role of function isSymmetric(TreeNode* root is pretty simple. First, it returns true if the tree is empty, and if it's not, it checks if its left child is a mirror of its right child, which happens in the isSymmetric(TreeNode* t1, TreeNode* t2). So let's try to understand how the second function works. It is essentially designed to take two trees and check if they are mirrors of each other. How? First, it does the obvious checks. If one is null and the other is not, it returns false, and if both are null it returns true. The interesting part happens when both are potentially trees. It suffices that the left child of one is the mirror of the right child of the other and vice versa. You can draw a tree to see why this is the case. A schema should be self-explanatory.

How to defind __eq__ func for a custom object which need to compare the the same class

I would like to implement an __eq__() method for an custom class Vertex.
However, when I carefully think about the problem, I find it is quite weird.
For example
class Vertex():
def __init__(self,node):
self.id = node
self.adjacent = {}
However for the adjacent dict, it store the data like this:
{neighbour_vertex1 : edge, neighbour_vertex2 : edge, ....}
If I want to implement the __eq__() method, it should look like:
def __eq__(self,other):
return self.id == other and self.adjacent == other.adjacent
but the self.adjacent == other.adjacent requires to compare the dicts
{neighbour_vertex1 : edge, neighbour_vertex2 : edge, ....}
{neighbour_vertex1 : edge, neighbour_vertex2 : edge, ....}
In order to compare them, I have to define the comparison function for neighbout_vertex which indeed is an instance of class Vertex.
I think it is like a chicken or egg question, any suggestion is appreciated.
Edit: example
class Vertex(object):
def __init__(self,id):
self.id = id
self.adjacent ={}
def add_vertex(self,obj):
self.adjacent.update(obj)
def __eq__(self,other):
return self.id == other.id and self.adjacent == other.adjacent
def __hash__(self):
return hash(id(self))
obj1 = Vertex("one")
obj2 = Vertex("two")
temp = {obj2:"connect 1-2"}
obj1.add_vertex(temp)
obj1s = Vertex("one")
obj2s = Vertex("two")
temp2 = {obj2s:"connect 1-2"}
obj1s.add_vertex(temp2)
if obj1 == obj1s:
print("True")
else:
print("False")
I came out with a simple example, first I do not want to modify the hash function, how can I modify the __eq__function to make the above code output
True instead of False
I don't think you need an __eq__ override here at all. With the design you've chosen, it doesn't make sense for two different instances of Vertex to represent "the same vertex", and two Vertex instances should only compare equal if they are actually the same object. The default __eq__ implementation already gives you that behavior.
If you do want different instances of Vertex to compare equal, then you need to think about your design first. For example, your definition of __hash__ as hash(id(self)) only makes sense if equality works by identity, so your __hash__ will need to be changed. You'll also need to think about things like, what if vertices a and b both have self.id = 1 and self.adjacent = {c: 'asdf'}, but c has self.adjacent = {b: 'asdf'}? Are a and b equal? You're going to have to come up with a precise definition of the concept of equality you want to use.
One possible redesign would be to move adjacency tracking out of the vertex objects. If vertex objects only have self.id, and edges are tracked externally by some sort of Graph object, then it could make sense to compare Vertex objects "by value". At that point, it might make more sense to eliminate the Vertex class entirely, though.
#Ralf suggested comparing only the id attribute. This is probably the best solution, and you should absolutely go with that if possible.
If not, what is the structure of your vertices? Is it like a tree where adjacency only goes one way? Then writing it like that is fine; eventually you'll run out of nodes.
If the vertices can loop back, we'll have to do something more complicated. The basic trick is to maintain a stack of vertices you haven't visited, and a list of nodes you've already compared. With each loop, pop the top element off the stack. If you see anything that would make the elements compare false, you can return. Otherwise, put the adjacent nodes on the stack if you haven't visited them before, update the visited nodes, and keep going.
(I won't be making the effort to provide a code sample.)

python set() membership and hashable objects

I wanted to store instances of a class in a set, so I could use the set methods to find intersections, etc. My class has a __hash__() function, along with an __eq__ and a __lt__, and is decorated with functools.total_ordering
When I create two sets, each containing the same two objects, and do a set_a.difference(set_b), I get a result with a single object, and I have no idea why. I was expecting none, or at the least, 2, indicating a complete failure in my understanding of how sets work. But one?
for a in set_a:
print(a, a.__hash__())
for b in set_b:
print(b, b.__hash__(), b in set_a)
(<foo>, -5267863171333807568)
(<bar>, -8020339072063373731)
(<foo>, -5267863171333807568, False)
(<bar)>, -8020339072063373731, True)
Why is the <foo> object in set_b not considered to be in set_a? What other properties does an object require in order to be considered a member of a set? And why is bar considered to be a part of set_a, but not foo?
edit: updating with some more info. I figured that simply showing that the two objects' hash() results where the same meant that they where indeed the same, so I guess that's where my mistake probably comes from.
#total_ordering
class Thing(object):
def __init__(self, i):
self.i = i
def __eq__(self, other):
return self.i == other.i
def __lt__(self, other):
return self.i < other.i
def __repr__(self):
return "<Thing {}>".format(self.i)
def __hash__(self):
return hash(self.i)
I figured it out thanks to some of the questions in the comments- the problem was due to the fact that I had believed that ultimately, the hash function decides if two objects are the same, or not. The __eq__ also needs to match, which it always did in my tests and attempts to create a minimal example here.
However, when pulling data from a DB in prod, a certain float was being rounded down, and thus, the x == y was failing in prod. Argh.

leaves_and_internals Function

This question is for school (homework) so I am not asking for code, and I don't want any, just an idea. I have to write a function that returns two lists, a list of the leaves and a list of the internal nodes of a binary tree. My algorithm is:
1) If both the left and the right subtrees are None, it is a leaf, and so I add it to the leaves list.
2) If they are not, then I add it to the internals list, and call the function on the left subtree, and then on the right, if they exist.
This is the code I have written:
def leaves_and_internals(self):
leaves = []
internals = []
if self.left is None and self.right is None:
leaves.append(self.item)
else:
internals.append(self.item)
if self.left != None:
leaves_and_internals(self.left)
else:
leaves_and_internals(self.right)
return internals, leaves
I'm pretty sure that the algorithm is correct, but I think that every time I recurse on the Nodes, the lists will get reset. How can I get around this?
Any help is greatly appreciated. Thanks
I have not looked into the algorithm of your code, and just merely suggesting an answer to the problem you're stuck at. You could pass leaves and internals as arguments to the recursive function, so that their contents get retained across the recursive calls.
In python, if you pass a mutable object to a function/method, the function/method gets a reference to the object. So as long as you still treat it as the same mutable object (i.e. not assign the parameter with something else directly), any changes you make to the object are also visible to the caller. Since list is a mutable type, this behavior is very much helpful for the case you're interested in.
And make sure to initialize the lists to [] before calling the leaves_and_internals function from outside.
def leaves_and_internals(self, leaves, internals):
if self.left is None and self.right is None:
leaves.append(self.item)
else:
internals.append(self.item)
if self.left != None:
leaves_and_internals(self.left, leaves, internals)
else:
leaves_and_internals(self.right, leaves, internals)
return
# Somewhere outside
leaves = []
internals = []
myobj.leaves_and_internals(leaves, internals)
UPDATE:
Since the OP mentions he cannot change the signature of the method nor use instance variables, this is an alternate solution I can think of which returns the leaves and internals to the caller. BTW, I assume some nodes in your tree can have both left and right, so you would need to check both (i.e. use 2 separate if instead of an if...else).
def leaves_and_internals(self):
leaves = []
internals = []
if self.left is None and self.right is None:
leaves = [ self.item ]
else:
if self.left != None:
leaves, internals = leaves_and_internals(self.left)
if self.right != None:
templeaves, tempinternals = leaves_and_internals(self.right)
leaves += templeaves
internals += tempinternals
internals.append(self.item)
return leaves, internals

Categories