Reputation: 135
I had a quick search but couldn't find anything that helped my problem.
I'm trying to make a program that takes the first 5 numbers and sources their product, and if that product is the largest found thus far it is set as such.
My code is:
string = str(integer)
x = 0
largest = 0
stringlength = len(string)
while x < stringlength:
a = int(string[x])
b = int(string[x+1])
c = int(string[x+2])
d = int(string[x+3])
e = int(string[x+4])
if (a*b*c*d*e > largest):
largest = a*b*c*d*e
print(largest)
x += 1
print(largest)
I excluded the integer value itself, but for reference it is 1000 digits long. Whenever I try to run this code I get "IndexError: string index out of range". Can anyone help?
Upvotes: 2
Views: 929
Reputation: 10867
string = str(integer)
x = 0
largest = 0
stringlength = len(string)
while x < stringlength-4: # going to -5 would be out of rangue
a = int(string[x])
b = int(string[x+1])
c = int(string[x+2])
d = int(string[x+3])
e = int(string[x+4])
if (a*b*c*d*e > largest):
largest = a*b*c*d*e
print(largest)
x += 1
print(largest)
Upvotes: 7
Reputation: 365707
This is a classic off-by-one error (or, in this case, off-by-4 error).
When x
reaches stringlength-4
, x+4
is stringlength
, which is past the end of string
. So, you need x < stringlength-4
, not x < stringlength
.
But you might want to consider rewriting your code to use higher-level abstractions, to make these problems harder to run into and easier to think about.
First, instead of this:
x= 0
while x < stringlength:
# ...
x += 1
Just do this:
for x in range(stringlength):
You could then solve your problem with this:
for x in range(stringlength-4):
But let's take it farther.
If you slice the string, you won't get an IndexError
:
for x in range(len(stringlength)):
a, b, c, d, e = map(int, string[x:x+4])
However, now you'll get a ValueError
in the unpacking. But really, you have no need to unpack into 5 separate variables here. Just keep the sequence and multiply it out. (You can do that with a loop, but in my opinion, this is one of the few cases reduce
is the most readable way to write something in Python.)
for x in range(len(stringlength)):
values = map(int, string[x:x+4])
prod = reduce(operator.mul, values)
if prod > largest:
largest = prod
print(largest)
Now there are no more errors—but that's because you're multiplying together the last 4, 3, 2, and 1 numbers. And that's exactly the problem: you never decided what should happen there.
So, now, you can make the decision explicit. Do you want to count them as batches, or skip them?
If you want to push even further forward, you can write sliding-window grouper functions using itertools
, one version that acts like zip
(stopping when the right edge of the window goes off the end of the list), one that acts like zip_longest
(stopping only when the left edge of the window goes off):
def groupwise(iterable, n):
groups = itertools.tee(iterable, n)
for i, group in enumerate(groups):
next(itertools.islice(group, i, i), None)
return zip(*groups)
def groupwise_longest(iterable, n, fillvalue=None):
groups = itertools.tee(iterable, n)
for i, group in enumerate(groups):
next(itertools.islice(group, i, i), None)
return itertools.zip_longest(*groups, fillvalue=fillvalue)
Now, you can just do this:
for group_of_five in groupwise_longest(string, 5, 1):
values = map(int, group)
prod = reduce(operator.mul, values)
if prod > largest:
largest = prod
print(largest)
Then, if you decide you'd rather not compare the incomplete groups at the end, just change the first line to:
for group_of_five in groupwise(string, 5):
Then you can move all the work outside the for
loop:
groups = groupwise_longest(string, 5, 1)
intgroups = (map(int, group) for group in groups)
prods = (reduce(operator.mul, group) for group in groups)
And now that we have a sequence of products, it should be obvious that to find the highest one, that's just:
print(max(prods))
For example:
>>> string = '12345678987654321'
>>> groups = groupwise(string, 5)
>>> intgroups = (map(int, group) for group in groups)
>>> prods = (reduce(operator.mul, group) for group in groups)
>>> max(prods)
28224
And notice that there's nowhere you could make an off-by-one errors, or any other "small" error. Of course you could still get something completely wrong, or just have no idea how to write it, but at least your errors will be obvious big errors, which are easier to debug.
Upvotes: 2