I'm trying to represent an array of evenly spaced floats, an arithmetic progression, starting at a0 and with elements a0, a0 + a1, a0 + 2a1, a0 + 3a1, ...
This is what numpy's arange() method does, but it seems to allocate memory for the whole array object and I'd like to do it using an iterator class which just stores a0, a1 and n (the total number of elements, which might be large).
Does anything that does this already exist in the standard Python packages?
I couldn't find it so, ploughed ahead with:
class mylist():
def __init__(self, n, a0, a1):
self._n = n
self._a0 = a0
self._a1 = a1
def __getitem__(self, i):
if i < 0 or i >= self._n:
raise IndexError
return self._a0 + i * self._a1
def __iter__(self):
self._i = 0
return self
def next(self):
if self._i >= self._n:
raise StopIteration
value = self.__getitem__(self._i)
self._i += 1
return value
Is this a sensible approach or am I revinventing the wheel?
Well, one thing that you are doing wrong is that it should be for i, x in enumerate(a): print i, x.
Also, I'd probably use a generator method instead of the hassle with the __iter__ and next() methods, especially because your solution wouldn't allow you to iterate over the same mylist twice at the same time with two different iterators (as self._i is local to the class).
This is probably a better solution which gives you random access as well as an efficient iterator. The support for the in and len operators are thrown in as a bonus :)
class mylist(object):
def __init__(self, n, a0, a1, eps=1e-8):
self._n = n
self._a0 = a0
self._a1 = a1
self._eps = eps
def __contains__(self, x):
y = float(x - self._a0) / self._a1
return 0 <= int(y) < self._n and abs(y - int(y)) < self._eps
def __getitem__(self, i):
if 0 <= i < self._n:
return self._a0 + i * self._a1
raise IndexError
def __iter__(self):
current = self._a0
for i in xrange(self._n):
yield current
current += self._a1
def __len__(self):
return self._n
Other answers answer the immediate problem. Note that if all you want is an iterator and you don't need random access, there's no need to write a whole iterator class.
def mylist(n, a0, a1):
for i in xrange(n):
yield a0 + i*a1
Only for reasons that are probably obvious to someone out there, iterating over mylist: for i,x in enumerate(a): print i,a doesn't return the values I expect but just a whole lot of references to the mylist instance. What am I doing wrong?
The culprit is print i,a. You are printing a, which is an array. You ought to print x instead. Chane this line to:
print i,x
Also a couple of things:
Change you class name to TitleCase. For e.g. class MyList or class Mylist.
It is a good idea to inherit from object if you are using Python 2.x. So class MyList(object): ...
You're enumerating over a, so printing it will print a lot of references to it. Print x instead.
Yes, there's a built-in generator for this (Python 2.7 and up):
import itertools
mygen = itertools.count(a0,a1)
If you don't have Python 2.7 yet (Python 2.4 and up):
import itertools
mygen = (a0 + a1*i for i in itertools.count())
Related
Here is the code I currently have.
def fibonacci(n):
if n == 1:
return 1
elif n == 2:
return 1
else:
value = fibonacci(n - 1) + fibonacci(n - 2)
return value
This currently takes quite some time to calculate values greater than n = 30. Is there a more computationally efficient method to accomplish this?
Adding a value cache to trade some memory for a reduced processing time can be a useful method. A purely recursive program will attempt to calculate values over and over again, however this takes time for larger values. If the values do not change, then storing them can be helpful. It is important to note, however, that should values be volatile you might need a different approach.
fibonacci_value_cache = {}
def fibonacci(n):
if n == 1:
return 1
elif n == 2:
return 1
elif n in fibonacci_value_cache:
return fibonacci_value_cache[n]
else:
fibonacci_value_cache[n] = fibonacci(n - 1) + fibonacci(n - 2)
return fibonacci_value_cache[n]
n = 100
print("Fib " + str(n) + ": " + str(fibonacci(n)))
Here, we check if the value is in the dictionary and return it if it is, otherwise we calculate it and add it to the dictionary. This means that we are make better use of the processor by not calculating the same value multiple times.
There's a recipe for a decorator that uses as an example exactly what you want. It's named Memoize in the PythonDecoratorLibrary.
It may seem like overkill, but having the memoized decorator around could be useful for other future tasks. That said, here it is in its entirety (although I changed the print at the end):
import collections
import functools
class memoized(object):
'''Decorator. Caches a function's return value each time it is called.
If called later with the same arguments, the cached value is returned
(not reevaluated).
'''
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
if not isinstance(args, collections.Hashable):
# uncacheable. a list, for instance.
# better to not cache than blow up.
return self.func(*args)
if args in self.cache:
return self.cache[args]
else:
value = self.func(*args)
self.cache[args] = value
return value
def __repr__(self):
'''Return the function's docstring.'''
return self.func.__doc__
def __get__(self, obj, objtype):
'''Support instance methods.'''
return functools.partial(self.__call__, obj)
#memoized
def fibonacci(n):
"Return the nth fibonacci number."
if n in (0, 1):
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(12))
Using idea of Dynamic Programming, and store the intermediate results to save computational cost, it could be very efficient. The code below cost less than 0.02s for n=10000 on my laptop.
def fib(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
for i in range(n):
result.append(b)
a, b = b, a + b
return result
No need for caching/memoization. Here's a Python 3 implementation that expresses the Fibonacci sequence as powers of a matrix, then does efficient exponentiation via halving and squaring. The result is O(log n) in both time and storage.
def matrix_fib(n):
if n == 1:
return [0,1]
else:
f = matrix_fib(n // 2)
c = f[0] * f[0] + f[1] * f[1]
d = f[1] * (f[1] + 2 * f[0])
return [c,d] if (n & 1) == 0 else [d,c+d]
def fib(n):
return n if n == 0 else matrix_fib(n)[1]
print(fib(1000000))
On my laptop this coughs up the value of the millionth Fibonacci number in a little over half a second, and the bulk of that is probably in the big integer arithmetic and formatting of the output—the result is ridiculously large. You don't need to worry about stack overflow, though. The call stack depth for this is only log2(1000000) = 20.
Suppose I convert the below pseudocode to Python. Regarding specifically the parameter indicated as 1st half of A, does Python have a mechanism like A[1..n/2] (another pseudocode shortcut I see from time to time) that does not require copy for passing part of a list as a parameter ?
Count(array A, length n)
if n = 1 return 0
else
x = Count(1st half of A, n/2)
y = Count(2nd half of A, n/2)
return x + y
Without such a mechanism I will pass indices as necessary.
The answer is no. You'll have to pass indices (or slice objects).
You could also write a list subclass that handles slices by returning "views" into the original list rather than copies. I've actually tackled this a few times and found it tricky to get completely right, but it's made much easier by the fact that your application doesn't need negative indexing, slice assignment, or the skip parameter. Here's a quick try:
class ListWithAView(list):
class ListView(object):
def __init__(self, list, start, stop, step):
self.list = list
self.start = start
self.stop = stop
self.step = step
def __iter__(self):
for i in xrange(self.start, self.stop, self.step):
yield self.list[i]
def __len__(self):
return (self.stop - self.start) / self.step
def __getitem__(self, i):
if isinstance(i, slice):
return type(self)(self.list, (i.start or 0) + self.start,
min(self.start + (i.stop or 0), self.stop),
i.step * self.step if i.step else self.step)
if isinstance(i, int) and i < len(self):
return self.list[i+self.start]
raise IndexError("invalid index: %r" % i)
def __setitem__(self, i, v):
if isinstance(i, int):
self.list[i+self.start] = v
else:
raise IndexError("invalid index: %r" % i)
def __repr__(self):
return "<slice [%s:%s:%s] of list id 0x%08x>: %s" % (self.start, self.stop, self.step, id(self.list), self)
def __str__(self):
return str(list(self))
__str__ = __repr__
#property
def view(self):
return self.ListView(self, 0, len(self), 1)
The view property of this list subclass returns a ListView object that acts much like a list, but gets and sets the data in the underlying list rather than storing any items itself. The returned object initially refers to the entire list but can be sliced further if desired. For simplicity, negative steps aren't handled, and you can't do slice assignment, just single items.
Quick demo:
seq = ListViwthAView(range(100))
view = seq.view[10:20][5:7]
view[0] = 1337
print seq[15] # 1337
You can sort of use slice objects here, but unfortunately there isn't a __len__ method, so you have to use (s.start + s.stop)/2 to compute the length. Any time you wise to "materialise" the subarray (which of course creates a copy), you can use A[s]
def count(A, s=None):
if s is None:
s=slice(0, len(A))
if s.start + 1 == s.stop:
return 1
else:
x = count(A, slice(s.start, (s.start + s.stop)/2))
y = count(A, slice((s.start + s.stop)/2, s.stop))
return x + y
print count([1,2,3,4,5])
In your example, the best solution is to just pass the list and the indices as you suggested.
If you didn't need to index into the slices (for example, if just having iterators over the first and second halves of the list was sufficient), you could use the islice function from itertools. E.g.
from itertools import islice
half = (len(sequence) + 1) // 2
first_half = islice(sequence, half):
second_half = islice(sequence, half, len(sequence))
Is it okay to use the yield statement in an instance method of a class? For example,
# Similar to itertools.islice
class Nth(object):
def __init__(self, n):
self.n = n
self.i = 0
self.nout = 0
def itervalues(self, x):
for xi in x:
self.i += 1
if self.i == self.n:
self.i = 0
self.nout += 1
yield self.nout, xi
Python doesn't complain about this, and simple cases seem to work. However, I've only seen examples with yield from regular functions.
I start having problems when I try to use it with itertools functions. For example, suppose I have two large data streams X and Y that are stored across multiple files, and I want to compute their sum and difference with only one loop through the data. I could use itertools.tee and itertools.izip like in the following diagram
In code it would be something like this (sorry, it's long)
from itertools import izip_longest, izip, tee
import random
def add(x,y):
for xi,yi in izip(x,y):
yield xi + yi
def sub(x,y):
for xi,yi in izip(x,y):
yield xi - yi
class NthSumDiff(object):
def __init__(self, n):
self.nthsum = Nth(n)
self.nthdiff = Nth(n)
def itervalues(self, x, y):
xadd, xsub = tee(x)
yadd, ysub = tee(y)
gen_sum = self.nthsum.itervalues(add(xadd, yadd))
gen_diff = self.nthdiff.itervalues(sub(xsub, ysub))
# Have to use izip_longest here, but why?
#for (i,nthsum), (j,nthdiff) in izip_longest(gen_sum, gen_diff):
for (i,nthsum), (j,nthdiff) in izip(gen_sum, gen_diff):
assert i==j, "sum row %d != diff row %d" % (i,j)
yield nthsum, nthdiff
nskip = 12
ns = Nth(nskip)
nd = Nth(nskip)
nsd = NthSumDiff(nskip)
nfiles = 10
for i in range(nfiles):
# Generate some data.
# If the block length is a multiple of nskip there's no problem.
#n = random.randint(5000, 10000) * nskip
n = random.randint(50000, 100000)
print 'file %d n=%d' % (i, n)
x = range(n)
y = range(100,n+100)
# Independent processing is no problem but requires two loops.
for i, nthsum in ns.itervalues(add(x,y)):
pass
for j, nthdiff in nd.itervalues(sub(x,y)):
pass
assert i==j
# Trying to do both with one loops causes problems.
for nthsum, nthdiff in nsd.itervalues(x,y):
# If izip_longest is necessary, why don't I ever get a fillvalue?
assert nthsum is not None
assert nthdiff is not None
# After each block of data the two iterators should have the same state.
assert nsd.nthsum.nout == nsd.nthdiff.nout, \
"sum nout %d != diff nout %d" % (nsd.nthsum.nout, nsd.nthdiff.nout)
But this fails unless I swap itertools.izip out for itertools.izip_longest even though the iterators have the same length. It's the last assert that gets hit, with output like
file 0 n=58581
file 1 n=87978
Traceback (most recent call last):
File "test.py", line 71, in <module>
"sum nout %d != diff nout %d" % (nsd.nthsum.nout, nsd.nthdiff.nout)
AssertionError: sum nout 12213 != diff nout 12212
Edit: I guess it's not obvious from the example I wrote, but the input data X and Y are only available in blocks (in my real problem they're chunked in files). This is important because I need to maintain state between blocks. In the toy example above, this means Nth needs to yield the equivalent of
>>> x1 = range(0,10)
>>> x2 = range(10,20)
>>> (x1 + x2)[::3]
[0, 3, 6, 9, 12, 15, 18]
NOT the equivalent of
>>> x1[::3] + x2[::3]
[0, 3, 6, 9, 10, 13, 16, 19]
I could use itertools.chain to join the blocks ahead of time and then make one call to Nth.itervalues, but I'd like to understand what's wrong with maintaining state in the Nth class between calls (my real app is image processing involving more saved state, not simple Nth/add/subtract).
I don't understand how my Nth instances end up in different states when their lengths are the same. For example, if I give izip two strings of equal length
>>> [''.join(x) for x in izip('ABCD','abcd')]
['Aa', 'Bb', 'Cc', 'Dd']
I get a result of the same length; how come my Nth.itervalues generators seem to be getting unequal numbers of next() calls even though each one yields the same number of results?
Gist repo with revisions |
Quick link to solution
Quick answer
You never reset self.i and self.nout in class Nth. Also, you should have used something like this:
# Similar to itertools.islice
class Nth(object):
def __init__(self, n):
self.n = n
def itervalues(self, x):
for a,b in enumerate(islice(x, self.n - 1, None, self.n)):
self.nout = a
yield a,b
but since you don't even need nout, you should use this:
def Nth(iterable, step):
return enumerate(itertools.islice(iterable, step - 1, None, step))
Long answer
Your code had an off-by-one smell that led me to this line in NthSumDiff.itervalues():
for (i,nthsum), (j,nthdiff) in izip(gen_sum, gen_diff):
If you swap gen_sum and gen_diff, you'll see that gen_diff will always be the one with nout greater by one. This is because izip() pulls from gen_sum before pulling from gen_diff. gen_sum raises a StopIteration exception before gen_diff is even tried in the last iteration.
For example, say you pick N samples where N % step == 7. At the end of each iteration, self.i for the Nth instances should equal 0. But on the very last iteration, self.i in gen_sum will increment up to 7 and then there will be no more elements in x. It will raise StopIteration. gen_diff is still sitting at self.i equal to 0, though.
If you add self.i = 0 and self.nout = 0 to the beginning of Nth.itervalues(), the problem goes away.
Lesson
You only had this problem because your code is too complicated and not Pythonic. If you find yourself using lots of counters and indexes in loops, that's a good sign (in Python) to take a step back and see if you can simplify your code. I have a long history of C programming, and consequently, I still catch myself doing the same thing from time to time in Python.
Simpler implementation
Putting my money where my mouth is...
from itertools import izip, islice
import random
def sumdiff(x,y,step):
# filter for the Nth values of x and y now
x = islice(x, step-1, None, step)
y = islice(y, step-1, None, step)
return ((xi + yi, xi - yi) for xi, yi in izip(x,y))
nskip = 12
nfiles = 10
for i in range(nfiles):
# Generate some data.
n = random.randint(50000, 100000)
print 'file %d n=%d' % (i, n)
x = range(n)
y = range(100,n+100)
for nthsum, nthdiff in sumdiff(x,y,nskip):
assert nthsum is not None
assert nthdiff is not None
assert len(list(sumdiff(x,y,nskip))) == n/nskip
More explanation of the problem
In response to Brian's comment:
This doesn't do the same thing. Not resetting i and nout is
intentional. I've basically got a continuous data stream X that's
split across several files. Slicing the blocks gives a different
result than slicing the concatenated stream (I commented earlier about
possibly using itertools.chain). Also my actual program is more
complicated than mere slicing; it's just a working example. I don't
understand the explanation about the order of StopIteration. If
izip('ABCD','abcd') --> Aa Bb Cc Dd then it seems like equal-length
generators should get an equal number of next calls, no? – Brian
Hawkins 6 hours ago
Your problem was so long that I missed the part about the stream coming from multiple files. Let's just look at the code itself. First, we need to be really clear about how itervalues(x) actually works.
# Similar to itertools.islice
class Nth(object):
def __init__(self, n):
self.n = n
self.i = 0
self.nout = 0
def itervalues(self, x):
for xi in x:
# We increment self.i by self.n on every next()
# call to this generator method unless the
# number of objects remaining in x is less than
# self.n. In that case, we increment by that amount
# before the for loop exits normally.
self.i += 1
if self.i == self.n:
self.i = 0
self.nout += 1
# We're yielding, so we're a generator
yield self.nout, xi
# Python helpfully raises StopIteration to fulfill the
# contract of an iterable. That's how for loops and
# others know when to stop.
In itervalues(x) above, for every next() call, it internally increments self.i by self.n and then yields OR it increments self.i by the number of objects remaining in x and then exits the for loop and then exits the generator (itervalues() is a generator because it yields). When the itervalues() generator exits, Python raises a StopIteration exception.
So, for every instance of class Nth initialized with N, the value of self.i after exhausting all elements in itervalues(X) will be:
self.i = value_of_self_i_before_itervalues(X) + len(X) % N
Now when you iterate over izip(Nth_1, Nth_2), it will do something like this:
def izip(A, B):
try:
while True:
a = A.next()
b = B.next()
yield a,b
except StopIteration:
pass
So, imagine N=10 and len(X)=13. On the very last next() call to izip(),
both A and B have self.i==0 as their state. A.next() is called, increments self.i += 3, runs out of elements in X, exits the for loop, returns, and then Python raises StopIteration. Now, inside izip() we go directly to the exception block skipping B.next() entirely. So, A.i==3 and B.i==0 at the end.
Second try at simplification (with correct requirements)
Here's another simplified version that treats all file data as one continuous stream. It uses chained, small, re-usable generators. I would highly, highly recommend watching this PyCon '14 talk about generators by David Beazley. Guessing from your problem description, it should be 100% applicable.
from itertools import izip, islice
import random
def sumdiff(data):
return ((x + y, x - y) for x, y in data)
def combined_file_data(files):
for i,n in files:
# Generate some data.
x = range(n)
y = range(100,n+100)
for data in izip(x,y):
yield data
def filelist(nfiles):
for i in range(nfiles):
# Generate some data.
n = random.randint(50000, 100000)
print 'file %d n=%d' % (i, n)
yield i, n
def Nth(iterable, step):
return islice(iterable, step-1, None, step)
nskip = 12
nfiles = 10
filedata = combined_file_data(filelist(nfiles))
nth_data = Nth(filedata, nskip)
for nthsum, nthdiff in sumdiff(nth_data):
assert nthsum is not None
assert nthdiff is not None
Condensing the discussion, there's nothing wrong with using yield in an instance method per se. You get into trouble with izip if the instance state changes after the last yield because izip stops calling next() on its arguments once any of them stops yielding results. A clearer example might be
from itertools import izip
class Three(object):
def __init__(self):
self.status = 'init'
def run(self):
self.status = 'running'
yield 1
yield 2
yield 3
self.status = 'done'
raise StopIteration()
it = Three()
for x in it.run():
assert it.status == 'running'
assert it.status == 'done'
it1, it2 = Three(), Three()
for x, y in izip(it1.run(), it2.run()):
pass
assert it1.status == 'done'
assert it2.status == 'done', "Expected status=done, got status=%s." % it2.status
which hits the last assertion,
AssertionError: Expected status=done, got status=running.
In the original question, the Nth class can consume input data after its last yield, so the sum and difference streams can get out of sync with izip. Using izip_longest would work since it will try to exhaust each iterator. A clearer solution might be to refactor to avoid changing state after the last yield.
The following code is to calculate nth term og fibonacci sequence in python using matrix exponentiation for various test cases t.But the program gives absurd output.Please tell me where i am wrong.when i ran the code in C++ it runs perfectly.
class matrix:
def __init__(self):
self.a=self.b=self.c=1
self.d=0
def mul(self,e,f):
ret = matrix()
ret.a=(e.a*f.a)+(e.b+f.c)
ret.b=(e.a*f.b)+(e.b+f.d)
ret.c=(e.c*f.a)+(e.d+f.c)
ret.d=(e.c*f.b)+(e.d+f.d)
return ret
def exp(self,a,p):
if(p==0):
temp=matrix()
temp.a=temp.b=temp.c=temp.d=1
return temp
if(p==1):
return a
if(p%2==0):
return self.exp(self.mul(a,a),p/2)
else:
return self.mul(a,self.exp(self.mul(a,a),(p-1)/2))
def fib(self,n):
if (n==0):
return 0
if (n==1):
return 1
s=matrix()
s=self.exp(s,n)
return s.d
t=int(raw_input())
while(t>0):
v=matrix()
n=int(raw_input())
print v.fib(n)
t=t-1
The problem lies in your __init__ function. In python the so-called variables are just 'tags' to data in the memory. To compare with C/C++, these can be thought of as pointers. when you assign self.a = self.b = self.c, you are basically assigning three different names to the same data in the memory. Any change you make in a will be reflected back in b and c and so on.
For your problem where you need three separate variables, one way to change the __init__ function is like:
self.a, self.b, self.c = 1, 1, 1
or you can use copy. copy() tells python to assign a new memory location and then assign the tag on the right hand side to that location. For more read the official documentation on this http://docs.python.org/2/library/copy.html. You can also read a short walk-through on this in Python Tutorial: Shallow and Deep-copy
There are several issues, in order of importance:
1) Your multiplication is wrong. Note the multiplications at the right where you have sums):
def mul(self,e,f):
ret = matrix()
ret.a=(e.a*f.a)+(e.b*f.c)
ret.b=(e.a*f.b)+(e.b*f.d)
ret.c=(e.c*f.a)+(e.d*f.c)
ret.d=(e.c*f.b)+(e.d*f.d)
return ret
2) In the last line, you do return s.d but you should return s.b or s.c or you will get one less fibonacci.
3) The line temp.a=temp.b=temp.c=temp.d=1 is not necessary because the constructor does the work. Besides it is wrong, because d should be 0.
4) Why are mul and exp class functions if they don't use self. It does no harm but they should be #staticmethod
5) Again, it does no harm but your second recursive call is unnecessarily complex. Just write:
return matrix.mul(a,matrix.exp(a, p-1))
I'm not sure if it is required for you to use matrix exponentiation for this problem. Unfortunately, I do not know much about Python classes quite yet. However, the following code does what the question heading wants: to find the n-th Fibonacci number. Below I describe this as F_n. Note the initial conditions for low values of n.
def fibN( n ):
"""
fibonacci: int -> int
Returns F_n.
Note: F_1 = 0, F_2 = 1, F_3 = 1, F_4 = 2
"""
n = abs( int( n ))
if n == 0:
fib = 0
elif n == 1:
fib = 1
else:
counter = 2
f0 = 0
f1 = 1
fib = f0 + f1
while counter <= n:
fib = f0 + f1
f0 = f1
f1 = fib
counter += 1
return fib
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?
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).
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)]).
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)