Getting the max value of attributes from a list of objects

PythonListAttributesMax

Python Problem Overview


I have this list of objects which have a x and a y parameter (and some other stuff).

path.nodes = (
    <GSNode x=535.0 y=0.0 GSLINE GSSHARP>,
    <GSNode x=634.0 y=0.0 GSLINE GSSHARP>,
    <GSNode x=377.0 y=706.0 GSLINE GSSHARP>,
    <GSNode x=279.0 y=706.0 GSLINE GSSHARP>,
    <GSNode x=10.0 y=0.0 GSLINE GSSHARP>,
    <GSNode x=110.0 y=0.0 GSLINE GSSHARP>,
    <GSNode x=189.0 y=216.0 GSLINE GSSHARP>,
    <GSNode x=458.0 y=216.0 GSLINE GSSHARP>
)

I need to have the max y of this list. Though, I tried this:

print(max(path.nodes, key=y))

And I get this error:

NameError: name 'y' is not defined

I am kinda new to Python and the docs give me no clue. I think I am doing wrong with the keyword because if iterate through nodes like this:

for node in path.nodes:
	print(node.y)

I'll get the values of y. Could somebody provide me an explanation?

Python Solutions


Solution 1 - Python

To get just the maximum value and not the entire object you can use a generator expression:

print(max(node.y for node in path.nodes))

Solution 2 - Python

There's a built-in to help with this case.

import operator

print(max(path.nodes, key=operator.attrgetter('y')))

Alternatively:

print(max(path.nodes, key=lambda item: item.y))

Edit: But Mark Byers' answer is most Pythonic.

print(max(node.y for node in path.nodes))

Solution 3 - Python

There is an important difference for when to use the "Pythonic" style #1 versus lambda style #2:

max(node.y for node in path.nodes)  # (style #1)

versus

max(path.nodes, key=lambda item: item.y)  # (style #2)

If you look carefully you can see that style #1 returns the maximum value for the attribute y while style #2 returns the node that has maximum attribute y. These two are not the same and code usage is important in case you want to iterate over the attribute values or iterate over the objects that holds that attribute.

Example:

class node():
    def __init__(self,x):
        self.x = x
        self.y = self.x + 10

node_lst = [node(1), node(2), node(3), node(4), node(5)]
print([(e.x,e.y) for e in node_lst])

>>> [(1, 11), (2, 12), (3, 13), (4, 14), (5, 15)]

Now:

maxy = max(node.y for node in node_lst)
print(maxy)
>>> 15

max_node = max(node_lst, key=lambda node: node.y)
print(max_node.y)
>>> 15

Solution 4 - Python

from operator import attrgetter
print(max(path.nodes, key=attrgetter("y")))

Solution 5 - Python

It's also possible to implement the __gt__ comparison operator for an object, and than use max without a key function:

class node:
    def __init__(self, y):
        self.y = y
    def __gt__(self, other):
        return self.y > other.y

and than something like:

ls = [node(3), node(5), node(11), node(0)]
print(max(ls).y)

is supposed to output 11.

Solution 6 - Python

y isn't defined as a variable; it's an attribute of individual GSNode objects; you can't use it as a name on its own.

To access the individual attributes you can use something like key=lambda x: x.y or attrgetter() from the operator module.

Solution 7 - Python

If y is a property attribute then you don't even need to import operator.attrgetter. You can use fget method instead:

my_node = max(path.nodes, key=Node.y.fget)

This will return the Node instance from where to get the max y value is just my_node.y

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPDXIIIView Question on Stackoverflow
Solution 1 - PythonMark ByersView Answer on Stackoverflow
Solution 2 - PythonFogleBirdView Answer on Stackoverflow
Solution 3 - Pythonuser-asterixView Answer on Stackoverflow
Solution 4 - PythonAlexey KachayevView Answer on Stackoverflow
Solution 5 - PythonbazView Answer on Stackoverflow
Solution 6 - PythonWoobleView Answer on Stackoverflow
Solution 7 - PythonGeorgyView Answer on Stackoverflow