trojek
trojek

Reputation: 3228

How to find maximum values from a list which contains objects in Python?

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

Answers (4)

Chris
Chris

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

Sede
Sede

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

cs95
cs95

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

juanpa.arrivillaga
juanpa.arrivillaga

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

Related Questions