问题
I have a custom data type, say: mytime
, which represent hours and minutes, such as 29:45, it is 29 hours and 45 minutes.
I want to use max
built-in function to find the item in a list of lists, whose sum of its elements is the greatest, where all lists contain values of mytime
type.
x = [[a, b], [c, d]]
a,b,c,d are of mytime
type.
max(x, key=sum)
won't work here, because a,b,c,d, are not integers.
If I type a + b
at python command line, I get the sum of these two time values, result is of mytime
type, without any errors.
How do I use max
function here?
回答1:
Let's say your class looks like this:
class mytime(object):
def __init__(self, h, m):
self.h = h
self.m = m
def __add__(self, other):
return mytime(self.h + other.h, self.m + other.m)
def __repr__(self):
return '%i:%i' % (self.h, self.m)
and you use it like this:
a = mytime(10, 10)
b = mytime(2, 22)
print a + b
and it will work as expect:
12:32
Problem:
What you want to do is:
l = [a, b]
print sum(l)
but it will fail:
TypeError: unsupported operand type(s) for +: 'int' and 'mytime'
The problem is that the sum
function will start with 0
and will add up all values of the list. It will try to evaluate
0 + mytime(10, 10)
which will fail.
Solution:
The solution to your problem is implementing the __radd__
function, which represents "reverse add" and is called when the arguments can't be resolved in the "forward" direction. For example, x + y
is evaluated as x.__add__(y)
if possible, but if that doesn't exist then Python tries y.__radd__(x)
.
So you can add the following method to your class:
def __radd__(self, other):
return mytime(self.h, self.m)
and the sum
function will work for you (in this implementation ignoring the other
value, which is probably fine in your case).
回答2:
You can write your own sum function:
def my_sum(item):
return sum(60 * e[0] + e[1] for e in item)
x = [[(2,0), (3,0)], [(9, 0), (4, 0)]]
print max(x, key=my_sum)
I have represented your mytime
data structure as tuples (with hours and minutes) so you may need to adjust my_sum
to your data structure. The only requirement is that the hours and minutes of a mytime
can be filled in for e[0]
and e[1]
respectively.
The above code returns the greatest element (in this case [(9, 0), (4, 0)]
).
回答3:
Are you sure using a + b
works? All sum
does is repeatedly apply +
to adjacent elements (it's the same as reduce(operator.add, sequence)
with a special case to break on strings)... So if it does work - then max(x, key=sum)
should just work -- as long as mydate
supports comparison operators - eg __gt__
, __eq__
, __lt__
Example
You need to have __gt__
defined for max to work...
class mydate(object):
def __init__(self, num):
self.num = num
def __add__(self, other): # make sure sum works
return self.num + other.num
def __gt__(self, other): # make sure max can do > comparison
return self.num > other.num
def __repr__(self):
return 'date: {}'.format(self.num)
x = mydate(3)
y = mydate(5)
z = mydate(2)
print max([x,y,z], key=sum)
来源:https://stackoverflow.com/questions/11520087/how-to-use-a-custom-function-in-maxx-key-custom-function-function