Reputation: 1146
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?
Upvotes: 65
Views: 79296
Reputation: 23
they already answered you, but if you want to get the object who has the max value:
max_val_object = lambda x: max(ob.value for ob in x)
Upvotes: 1
Reputation: 6234
from operator import attrgetter
print(max(path.nodes, key=attrgetter("y")))
Upvotes: 5
Reputation: 936
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
Upvotes: 44
Reputation: 76762
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))
Upvotes: 37
Reputation: 838116
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))
Upvotes: 115
Reputation: 1587
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.
Upvotes: 4
Reputation: 13697
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
Upvotes: 0
Reputation: 89877
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.
Upvotes: 0