From Point class to Linestring class - python

I have created a Point class that takes x,y coords as arguments. Also I wanted to create a Linestring class that takes as many arguments as the user wants and store them as points. So far :
class Point(object):
def __init__(self,x,y):
self.x = x
self.y = y
def move(self,movex,movey):
self.x += movex
self.y += movey
class LineString(object):
def __init__(self, *args):
self.points = [Point(*p) for p in args]
So now I have stored in self.points a list of points.
The questions is how can I use the move function of points, in the class linestring.
I tried something like that but it does not work
def moveline(self,movex,movey):
self.points.move(movex,movey)

To spell out exactly what #MichaelButscher stated in the comments, the issue with your moveline function is that self.points is a list of Point objects rather than a Point object itself. Therefore, we need to iterate through this list and call the move function for each of these Point objects. This can be accomplished with a for loop. Your updated moveline function could look like this:
def moveline(self,movex,movey):
for point in self.points:
point.move(movex,movey)

Related

Check if an object is in a set (Python)

Let say I have the following Point Class.
class POINT:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
Main function:
def main():
mySet = set()
a = POINT(1,2)
mySet.add(a)
b = POINT(1,2)
print("B is in mySet= {}".format(b in mySet))
I would like to know an efficient way to check if an object(a point) is in a set.
I know two ways to accomplish it, but they are either not efficient or don't use a custom object:
Traverse through all the point objects in the set --> O(n)
Use set to represent points. i.e (1,2) in mySet --> not using a custom object
I believe when using the key term in, it will check the id or hash values of objects. I wonder what key term allows me to check the values of objects in a set.
We could rephrase this question to "how to use in key term with a custom object?"
We need to define hash in the custom class. How do we do it?
We need to consider two main cases:
Avoid collision
Efficient
We could get collision if we define hash = self.x + self.y because Point(x,y) and Point(y,x) would give the same hash values and it shouldn't be since their x's and y's are not the same.
One way to avoid it is by using a built-in hash function that takes objects. We could convert our self.x and self.y to a tuple object so that it can be used with the hash function. The efficient of this would be depend on how Python implements the hash().
class POINT:
def __hash__(self):
return hash((self.x, self.y))

instance variable not modified in a for loop

I have a class with instance variables which I want to modify in a loop using a class method, simplified version of what I'm doing:
class Example:
def __init__(self,x,z):
self.x=x
self.z=z
def run(self,y):
temp_list=[self.x, self.z]
for ind,item in enumerate(temp_list):
temp_list[ind] = temp_list[ind]+y
print (self.x, self.z)
ex = Example(5,6)
ex.run(5)
The output I get is [5,6] instead of the desired [10,11].
I was wondering if anyone could point me to an explanation as to why this happens?
In run(), you create a list of 2 items, the value self.x and self.z. Next, you iterate over that list, and modify each value by adding y to it.
After the for-loop, temp_list will be [10, 11], but you have not modified self.x or self.y in any way.
Hence, the print() call will print the unmodified self.x and self.y values, being 5 and 6 in your example.
If you don't actually write self.x = ..., then you can generally assume that self.x will not be modified. When you write temp_list[ind] + y and store it in temp_list[ind], you're updating the list with a new value, which has no bearing on any values that other variables happen to hold (including your object's x variable).
To get the desired result with code similar to yours, you could do something like this:
class Example:
def __init__(self,x,z):
self.list=[x, z]
def run(self,y):
for ind,item in enumerate(self.list):
self.list[ind] = self.list[ind]+y
print (self.list)
ex = Example(5,6)
ex.run(5)
This would create a self.list item in your init definition that would then be used to iterate over the initial values and add your y value to it. The main error you had was printing an unaltered list (but you were on the right track!)
Hope this helps!
You can use, the example under.
class Example:
def __init__(self, x, z):
self.x = x
self.z = z
def run(self,y):
# Put your init arguments into the array
result = [self.x, self.z]
# Modify your init arguments
for x in range(len(result)):
result[x] += y
# Return the array with new values
return result
ex = Example(5, 6)
print(ex.run(5))
Maybe the link would be helpful for you, learn for loop in python

Sorting Objects based on properties

I am trying to sort the Points based on the X and Y properties of the point object.A small example below to explain my process:
class Point:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return '[{},{},{}]'.format(self.x, self.y, self.z)
#point instances
p1,p2,p3 = Point(7,85,5), Point(56,16,20), Point(24,3,30)
point_list = [p1,p2,p3]
def get_X(point):
return point.x
def get_Y(point):
return point.y
sorted_points = sorted(point_list, key = get_X)
# print(sorted_points) // [[7,85,5], [24,3,30], [56,16,20]]
sorted_points = sorted(sorted(point_list, key = get_X), key = get_Y)
# print(sorted_points) // [[24,3,30], [56,16,20], [7,85,5]]
But I need an output like this sorting X first keep them in same order and then sort Y
[[7,3,5], [24,16,30], [56,85,20]]
I think I am trying to exchange the properties of each instances by achieving the above, But I don't know how to do that.
Tuples will naturally sort in the way you want. You can simplify things by adding a __lt__() function to your class. Sorted will use this function to compare. Then you can depend on the natural sorting order of tuples easily with something like this:
class Point:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return '[{},{},{}]'.format(self.x, self.y, self.z)
def __iter__(self):
return iter((self.x, self.y, self.z))
def __lt__(self, other):
return (self.x, self.y, self.z) < (other.x, other.y, other.z)
#point instances
point_list = [Point(7,85,5), Point(56,16,20), Point(24,3,30), Point(7, 20, 0), Point(56,16,15)]
sorted(point_list)
# --> [[7,20,0], [7,85,5], [24,3,30], [56,16,15], [56,16,20]]
EDIT: Create new points
To create new points by combining the sorted elements of each point individually you can unzip your points, sort them and then zip them again. The nicest way to do this is to add an __iter__() function to your class to make it iterable so it can support zip. I've done this in the code above. This will allow you to do this:
point_list = [Point(7,85,5), Point(56,16,20), Point(24,3,30), Point(7, 20, 0), Point(56,16,15)]
newTuples = list(zip(*[sorted(l) for l in zip(*point_list)]))
sortedPoints = [Point(*p) for p in newTuples ]
#sortedPoint => [[7,3,0], [7,16,5], [24,16,15], [56,20,20], [56,85,30]]
This also sorts the z values, but it's easy enough to change that if you need it for some reason.
By placing the key elements in tuples in the order you want them sorted (primary value first, secondary value second), the ordering method of tuples will automatically perform in the way you are hoping to achieve.
All you need to change is that your value for key should be set to key=get_XY, where get_XY returns a tuple of x and y coordinates:
def get_XY(point):
return point.x, point.y

What happens in this class?

I am trying to alter a program, but i first need to fully understand the code.
class Coordinate:
def __init__(self,x,y):
self.x = x
self.y = y
def equal_to(self,coordinate):
return coordinate.x == self.x and coordinate.y == self.y
def merge_together(self,coordinate_together):
return Coordinate(self.x+coordinate_together.x,self.y+coordinate_together.y)
What is the functionality of this class?
I can't understand -- especially the return coordinate.x and coordinate.y parts.
::merge_together sums (Euclidean translation) the ordinates, returning a new Coordinate instance.
::equal_to compares two Coordinate objects (but perhaps should be using the __eq__ idiom -- along with related methods).
it returns True if coordinate.x == self.x AND coordinate.y == self.y.
(looks like same position)
The method expects and instance of Coordinate probably (see below the same object)

Two objects in a method from a class?

I'm having a small issue with this code, I am currently learning about classes and trying to separate the two objects I have created to use both of them in a method from the class.
import math
class Segment:
def __init__(self, xcoord = 0, ycoord = 0):
self.x = xcoord
self.y = ycoord
def get(self):
return (self.x, self.y)
def setx(self, xcoord):
self.x = xcoord
def sety(self, ycoord):
self.y = ycoord
def length(self, xcoord, ycoord):
return math.sqrt(math.pow(xcoord-ycoord,2)+(xcoord-ycoord,2))
p1 = Segment(3,4)
p2 = Segment()
p2.setx(5)
p2.sety(5)
s = Segment(p1,p2)
print(Segment.get(p1))
print(Segment.get(p2))
print(s.length())
I know that I am missing parameters in my length() method, or perhaps I have not? I would like to understand how I am able to have the objects interact with on another after I have defined them.
For further clarity, I am trying to print the distance between the two objects using the parameters I have assigned to them.
Okay, let's forget the code for a second. Firstly, let's talk about naming things. Your Segment class is not a class of segments - it's a class of points. So let's start by renaming your class Point.
class Point:
def __init__(self, xcoord = 0, ycoord = 0):
self.x = xcoord
self.y = ycoord
Better already, no?
Now, imagine you're looking at someone else's code, trying to use that. Their Points have a length() method that you can call. What do you expect that to do? What could that... possibly do? A number of things, all because length is an awful descriptor for something that a Point is doing. It's certainly not a property of the Point - a point is 0-dimensional.
So let's rethink that function. There are two obvious ways to make this API - your Point class could have a distance_to(other_point) method, that would accept one argument - another Point. Optionally, you could have a module-level function segment_length(point1, point2) that would give you the length of the segment defined by the two Point objects.
So, the module-level function:
def segment_length(p1, p2):
return math.sqrt((p2.x-p1.x)**2 + (p2.y-p1.y)**2)
I'll leave the Point method to you, should you wish to attempt it. It looks very similar, just using self in lieu of one of the points.
Lets walk through this:
p1 is an instance of the Segment class with attributes x=3, y=4.
p2 is an instance of the Segment class with attributes x=0, y=0,
When you set p2 to (5, 5) you could do it with p2 = Segment(5, 5),
s will have attributes x=p1 (an instance of Segment, not a coordinate) and y=p2 (another instance of Segment).
Calculating the length.
Your length method should look like this:
def length(self, xcoord, ycoord):
return math.sqrt(math.pow(xcoord - self.x,2)+math.pow(ycoord - self.y,2))
This now uses the x and y coordinates of the class instance (in the example below, p1) and calculates the length between them, and the xcoord and ycoord parameters provided.
And you would call this with:
p2x, p2y = p2.get()
print(p1.length(p2x, p2y))
Firstly, you're missing a second math.pow() in your line:
return math.sqrt(math.pow(xcoord-ycoord,2)+(xcoord-ycoord,2))
Secondly with your call s = Segment(p1, p2) the x and y values of your Segment s are equal to the segments p1 and p2.
At the moment your values should read:
p1.get()
> (3, 4)
p2.get()
> (5, 5)
After the assignment of s you get:
s.get()
> ((3, 4), (5, 5))
This is problematic, because math.pow() has no idea what to do with a Segment object.

Categories