Is there any way to find an object saved in a list, knowing only its parameters and without traversing the said list?
For example, there's a class, objects of which have an (x;y) coordinate, and none of the objects share the same coordinate (all x/y pairs are distinct and do not repeat). These objects are all saved in a list:
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
points = [Point(...), Point(...), Point(...), Point(...), ...]
Whenever I need the specific instance, is there any way to find it (here: its index in the list) by using just its coordinates without traversing the whole list like here:
def find_objects_index(x, y):
for i in range(len(points)):
if points[i].x == x and points[i].y == y:
return i
EDIT: these Point()s are to be accessed for writing, not reading, and so object.x and object.y will be changing, you can't just create a dictionary with (object.x, object.y) as keys - you'd need to add a new entry and delete the old one each time.
You can use list aggregation with a condition to get the item(s) you are looking for:
matching = [p for p in points if p.x = VALX and p.y == VALX]
However, in this case having a dictionary with (x, y) as key is most likely the correct (and well performing) way to go.
Is there any way to find an object saved in a list, knowing only its
parameters and without traversing the said list?
Short answer: No.
If you want or need to traverse such a collection of data points rapidly, perhaps you should consider using an type other than a list--a binary tree based off x or y data, for example (or if you need to track them separately, perhaps one tree for each)?
Just put the Points in a dict():
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
points_list = [Point(...), Point(...), Point(...), Point(...), ...]
points_dict = {(p.x,p.y):p for p in points_list}
def find_object(x, y):
if (x,y) in points_dict:
return points_dict[(x,y)]
def replace_object(x, y, new_point):
points_dict.pop((x, y), None)
points_dict[(new_point.x, new_point.y)] = new_point
Related
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))
I have a "Node" class which takes as arguments x and y. The class methods calculate different values. I have multiple instances of this class called "nodes". What I want is to find the node with the lowest "fcost" and get the x and y coordinates of that node.
I have no idea how to solve this problem so it would be much appreciated if you could help me.
class Node():
# Node class
def __init__(self, y, x):
self.y = y
self.x = x
def gcost(self):
return self.x + self.y
def hcost(self):
return self.x * self.y
def fcost(self):
return self.gcost() + self.hcost() # method that indicates
# which node to choose
node1 = Node(5,5)
node2 = Node(2,2)
nodes = [node1, node2] # I actually don't know if I should create a
# list of nodes so please tell me if I should
# not
### CODE TO SOLVE THE PROBLEM ###
In this case the lowest fcost between node1 and node2 is node2's fcost so I expect the output to be:
(2,2) or [2,2]
Either a list or a tuple, either way is fine.
You should use the min() function. You can use it in different ways, but in this scenario, I think that the simplest solution would be to use a lambda function - which is a shorter way to write and define functions in python.
You can read more about the min() function here, and more about lambda functions here.
Anyway, this piece of code should work just fine:
class Node():
# Node class
def __init__(self, y, x):
self.y = y
self.x = x
def gcost(self):
return self.x + self.y
def hcost(self):
return self.x * self.y
def fcost(self):
return self.gcost() + self.hcost()
node1 = Node(5,5)
node2 = Node(2,2)
nodes = [node1, node2]
needed_node = min(nodes, key=lambda x:x.fcost())
needed_list = [needed_node.x, needed_node.y] # in case you want the result as a list
needed_tuple = (needed_node.x, needed_node.y) # in case you want the result as a tuple
Use min(list, key=...).
min_node = min(nodes, key=lambda n:n.fcost())
print(min_node, min_node.fcost(), min_node.x, min_node.y)
key has to be name of function.
min will use it to get value which it will compare to find minimal one.
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
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
I have a list of vectors
vector1=[1,1]
vector2=[2,2]
favoritevector=[1,-1]
Then a list of those vectors
vectors=[]
vectors.append(vector1)
vectors.append(vector2)
vectors.append(favoritevector)
vector
>>vector = [[1,1], [2,2], [1,-1]]
How can I retrieve the names of the objects inside the list vectors, instead of the actual value of the objects.
In this case, I would like to something that if I ask for the element 0 of the list vectors the function or command returns to me the name "vector1" instead of [1,-1].
Thanks in advance for the help.
I don't think there is a way to do this using a list. You might try something like this:
class vector(object):
def __init__(self, name, x, y):
self.name = name
self.x = x
self.y = y
def __repr__(self):
return """<vector {} {}>""".format(self.name, (self.x, self.y))
Then, you can do:
vectors = []
vectors.append(vector(name="vector1", x=1, y=2))
vectors.append(vector(name="vector2", x=2, y=3))
# to get the name of the first vector, do:
vectors[0].name
# 'vector1'
If the order of the vectors is not important you can use dictionaries
vectors_dict["vector1"] = [1, 1]