(This is Project Euler Problem 14)
I'm trying to diversify my Python skills by using Itertools.
I want to get the index of a maximum returned value in a set number of iterations (1,000,000) from a generator in Python's itertools.
The function works, butt I can't figure out how to get to effectively get the maximum value without storing it in a massive one-million long list which I think could hardly be efficient to this. Is there an intelligent smart way? (edit: Maybe this is the easiest way?)
The current code is that at the moment it stops when the chain reaches 100 which is wrong.
#Project Euler Problem 14
#Which starting number, under one million, produces the longest chain?
import itertools
def length():
x=1
while True:
l=0
c=x #Create the running integer.
while c>1:
if c%2==0:
#Number is even, divide it by two.
c=c/2
l+=1
else:
#Number is odd, multiply by three and add one.
c=3*c+1
l+=1
yield l+1 #Add the final one as well and show the chain length.
x+=1 #Increment
print list(itertools.takewhile(lambda x:x<100,length()))
I approached the problem as follows:
import functools
def euler_014(max_=1000000):
longest = max_len = None
for n in range(1, max_):
length = len_collatz(n)
if max_len is None or length > max_len:
max_len, longest = length, n
return longest
def memoize(f):
cache = {}
@functools.wraps(f)
def func(*args):
if args not in cache:
cache[args] = f(*args)
return cache[args]
return func
@memoize
def len_collatz(n):
if n == 1:
return 1
if n % 2:
n = (n * 3) + 1
else:
n //= 2
return 1 + len_collatz(n)
Here memoize
makes things more efficient by storing previous results for len_collatz
, len_collatz
tells you the length of the sequence from n
to 1
(without actually generating a list of the whole sequence) and euler_014
simply has to keep track of the longest length and the associated value of n
. Note that it doesn't keep all of the results - just the length of the longest series so far and the value of n
that produced that sequence.