I have a Node class defined as follows (I only copied the relevant code for simplification):
class Node(object):
def __init__(self, x, y):
self.x = x
self.y = y
self.neighbours = []
I also have a dictionary that has Node objects as key, and the key-node's list of neighbours as value for each key.
successorTable = {
Node(0, 1): [Node(1, 0)],
Node(1, 0): [Node(0, 1)],
# and so on ...
}
Now what I would like to do is to get the dictionary's key (Node object) having the maximum value of x and the key having the maximum value of y
So I basically am trying to get the following result:
# maxXNode -> Node(1, 0)
# maxYNode -> Node(0, 1)
Your problem
First, for you problem you can do this.
max_x = max(successorTable.keys(), key=lambda n: n.x)
max_y = max(successorTable.keys(), key=lambda n: n.y)
Other problems
Then a word on your code.
I suggest you be careful with using your Node's as dictionary key as you didn't define __hash__ and __eq__ methods.
d = {}
d[Node(0, 0)] = 0
d[Node(0, 0)] # raises a KeyError
By default, an object is hashed and compared by its id, so two nodes with the same coordinates will not hash to the same value. You might want to fix this like so.
class Node(object):
def __init__(self, x, y):
self._x = x
self._y = y
self.neighbours = []
#property
def x(self):
return self._x
#property
def y(self):
return self._y
def __hash__(self):
return hash((self.x, self.y))
def __eq__(self, other):
return (self.x, self.y) == (other.x, other.y)
We use _x, _y and property to emphasize the fact that those attributes should not be updated as they are used for hashing.
Related
I'm sorry for the confusing title. I am not entirely sure how to define my problem.
So, I would like to make a vector class where it is possible to assign the x- and y-attributes by using vec[item] = value.
Since I have trouble explaining it, this is basically what I want:
vec = Vec(1,3)
vec[0] = 2
print(f'x-coordinate is: {vec.x}')
I would like this statement to print: x-coordinate is: 2. As of now it prints x-coordinate is: 1
How do I implement this properly in my Vec class?
This is part of the Vec class. I'm trying to use __setitem__()
class Vec():
def __init__(self, x, y):
self.x = x; self.y = y
self.lis = [self.x,self.y]
self.dic = {'x' : self.x, 'y': self.y}
def __getitem__(self, item):
if isinstance(item, int):
return self.lis[item]
if isinstance(item, str):
return self.dic[item]
# What I've tried
def __setitem__(self, item, value):
if isinstance(item, int):
self.lis.__setitem__(item, value) #<--?
self.lis[item] = value #<--?
if isinstance(item, str):
return self.dic.__setitem__(item, value)
I hope my problem is understandable.
(I apologize for my naming of things - It is not my strong suit)
You should do
def __setitem__(self, item, value):
if isinstance(item, int):
if item == 0:
self.x = value
elif item== 1:
self.y = value
Primitive types are copied by value, not by reference.
I have two Point objects and the code looks like this:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
a = Point(1, 3)
b = Point(4, 2)
max(a, b) # Make this output Point(4, 3)
My question is: "How can I implement a custom max function for the Point class that will return Point(max(self.x, other.x), max(self.y, other.y))?" The max function seems to just look at the __lt__ and return the highest.
max() can't do this, it can only return one of the elements given as input, not produce new instances.
You need to implement your own function:
def max_xy_point(*points):
if not points:
raise ValueError("Need at least 2 points to compare")
if len(points) == 1:
points = points[0]
return Point(
max(p.x for p in points),
max(p.y for p in points)
)
Like the built-in max() function, this can take either a single sequence (max([p1, p2, p3, ...]) or separate arguments (max(p1, p2, p3, ...)).
max(a, b) can return only a or b - it can't create point with new values.
You may add own method to class and use
c = a.max(b)
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def max(self, other):
return Point(max(self.x, other.x), max(self.y, other.y))
a = Point(1, 3)
b = Point(4, 2)
c = a.max(b)
print(c.x, c.y)
You can go about it like this, to get desired output:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def max(self, other):
if not isinstance(other, Point):
return NotImplemented
return Point(max(self.x, other.x), max(self.y, other.y))
def __repr__(self):
return f'Point{self.x, self.y}'
a = Point(1, 3)
b = Point(4, 2)
a.max(b)
# Point(4, 3)
I have a point class in python (Python36-32)
class point:
def __init__(self , xPoint ,yPoint):
self.x = xPoint
self.y = yPoint
def makeMeStr(self):
return "("+str(self.x)+","+str(self.y)+")"
def __repr__(self):
return self.makeMeStr()
def __str__(self):
return self.makeMeStr()
when i create a list of these points and when I do
left, right = zip(*myListOfPoint)
i get
TypeError: zip argument #1 must support iteration
Any suggestion please
To support iteration add __iter__() method to your class (that method will yield x and y values from point):
class point:
def __init__(self , xPoint ,yPoint):
self.x = xPoint
self.y = yPoint
def makeMeStr(self):
return "("+str(self.x)+","+str(self.y)+")"
def __repr__(self):
return self.makeMeStr()
def __str__(self):
return self.makeMeStr()
def __iter__(self):
yield self.x
yield self.y
list_of_points = [point(1, 2), point(3, 4), point(5, 6)]
left, right = zip(*list_of_points)
print(left) # this will print all x values
print(right) # this will print all y values
Will print:
(1, 3, 5)
(2, 4, 6)
I will provide an example of the problem in question, in case the title was not clear enough.
Let's say that I have a class Point(object) that represent 2d coordinates.
Is it possible to create a "magic" method that will allow the following?
x, y = point
Maybe some hacks with iterators?
you can simply tap into the iterator protocol of the object and accomplish this
class Point(object):
def __init__(self, x,y):
self.x = x
self.y = y
self.points = (x,y)
def __iter__(self):
return iter(self.points)
p = Point(1,5)
x,y = p
print x,y
# 1,5
take a look at http://www.rafekettler.com/magicmethods.html#sequence on more information on how a custom object can be converted into an iterable; or more precisely how one would use an object like an iterable.
Just provide an __iter__ method.
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __iter__(self):
yield self.x
yield self.y
p = Point(1, 2)
x, y = p
assert (1, 2) == (x, y)
Be careful though. This means your class suddenly becomes safe to use in many other places where it might have previously thrown a type error.
eg.
def add_1(x):
return x + 1
l = list(map(add_1, p)) # works, because the point is iterable
Ergo, you may want to provide a method other than __iter__ that provides the iterator.
eg.
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def coords(self):
yield self.x
yield self.y
p = Point(1, 2)
x, y = p.coords()
assert (1, 2) == (x, y)
Generally if we need to insert an object to a set, we should make it hash-able (by implementing the hash function) and comparable (and implementing a compare function). Set does not provide a mechanism to access its elements and thus cannot be mutated directly though can easily be circumvented.
A general pattern to mutate a set item would be as follows
i = next(iter(x))
update(i)
x.add(i)
This generally seem to work for almost all cases except one when unexpected holes are created.
class Foo(object):
def __init__(self, x):
self.x = x
self.count = 0
def __hash__(self):
return hash((self.x, ))
def __iadd__(self, n):
self.count += n
def __eq__(self, other):
return self.x == other.x
>>> x = {Foo(1)}
>>> i = next(iter(x))
>>> i+=1
>>> x.add(i)
>>> x
set([None, <__main__.Foo object at 0x0279D8B0>])
My guess is mutating a set element while updating may cause unexpected behavior but invoking next would just fetch the value (a copy I guess) that should not be an issue.
Any idea what the problem may be?
Per the docs,
[__iadd__] should attempt to do the operation in-place (modifying self) and
return the result (which could be, but does not have to be, self)
Therefore,
def __iadd__(self, n):
self.count += n
return self
Then,
class Foo(object):
def __init__(self, x):
self.x = x
self.count = 0
def __hash__(self):
return hash((self.x, ))
def __iadd__(self, n):
self.count += n
return self
def __eq__(self, other):
return self.x == other.x
x = {Foo(1)}
i = next(iter(x))
i+=1
x.add(i)
print(x)
yields
set([<__main__.Foo object at 0x7f19ae8b9f10>])
You probably want to return self in iadd method.