Reputation: 3228
I have a class:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
I create a list of objects of the above class Point which has field x
and y
.
I want to find maximum values of x
or y
of all objects from the list. For example from list [Point(1,3), Point(5,2), Point(8,0)]
it would be 8.
I can do it as follows:
new_list = []
for point in points_list:
new_list.append(point.x)
new_list.append(point.y)
max(new_list)
What is the most elegant way to do it in Python?
Upvotes: 0
Views: 4921
Reputation: 22953
While you can use max()
and key
like @Coldspeed said, in the long term I believe a better solution would be to overload the less than and greater than operators for your Point
class. That way you only have to implement the logic once. Also, if you decide to change the logic in the future, you'll only have to change it in one place:
>>> class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __gt__(self, point):
return self.x > point.x or self.y > point.y
def __lt__(self, point):
return self.x < point.x or self.y < point.y
>>> points = [Point(1,3), Point(5,2), Point(8,0)]
>>> point = max(points)
>>> point.x
8
>>>
if you want to get the maximum value you can use a simple ternary condition:
max_val = point.x if point.x > point.y else point.y
Upvotes: 3
Reputation: 61225
You can use vars
to return a dictionary of your instance's attributes then use the .values
method to access the values.
>> class Point(object):
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
>>> points = [Point(1,3), Point(5,2), Point(8,0)]
>>> max_obj = max(points, key=lambda p: max(vars(p).values()))
>>> max_obj.x
8
If you are only interested in the maximum value, you can do something like this:
>>> max(map(lambda p: max(vars(p).values()), points))
8
If you find yourself frequently doing this, then you may want to implement the rich comparison ordering methods for your class and an instance method which returns the maximum value for the attribute.
In [7]: import functools
In [8]: @functools.total_ordering
...: class Point(object):
...: def __init__(self, x, y):
...: self.x = x
...: self.y = y
...: def max_attr_value(self):
...: return max(vars(self).values())
...: def __eq__(self, other):
...: return self.max_attr_value() == other.max_attr_value()
...: def __lt__(self, other):
...: return self.max_attr_value() < other.max_attr_value()
...:
In [9]: points = [Point(1,3), Point(5,2), Point(8,0)]
In [10]: max(points).max_attr_value()
Out[10]: 8
Upvotes: 2
Reputation: 402403
You can use the max
function with a key:
max_obj = max(your_list, key=lambda p: p.x if p.x > p.y else p.y)
To get the maximum value, you can do
max_val = max_obj.x if max_obj.x > max_obj.y else max_obj.y
print(max_val)
Or (as OP suggests)...
max_val = max(max_obj.x, max_obj.y)
print(max_val)
Upvotes: 7
Reputation: 95938
Pretty straightforward if you can choose the attributes you want to consider beforehand:
>>> points = [Point(1,3), Point(5,2), Point(8,0)]
>>> max(getattr(p, attr) for p in points for attr in ('x','y'))
8
>>>
Upvotes: 2