Indexing error when comparing numbers in list - python

I'm trying to build a function that given a list or string of numbers (for the string the numbers are separated by ",") and a target number finds the number of values in the last that can get to the target. Numbers can increase by 1 only by eating a number equal or smaller than themselves, after eating the smaller number the smaller number is removed from the list. The list resets to it's original for every number. I am close but I keep getting an index error and I'm not sure how to fix it
def cannibal(l, target):
newl = l
count = 0
i = 0
listlen = len(newl)
try:
newl = l.split(",")
newl.sort(reverse = True)
newl = list(map(int, newl))
print (newl)
except:
newl.sort(reverse = True)
print (newl)
finally:
while i < len(newl):
print ("index is ",i)
if newl[i] == target:
print ("match found at ", i)
count += 1
i += 1
continue
if newl[i] > target:
i += 1
continue
for j in range(i+1,listlen-1):
print ("list length is",listlen)
while newl[i] > newl [j] and j<listlen:
print (newl[i]," is eating ",newl[i+1])
newl.remove(newl [i+1])
newl[i] = newl[i]+1
listlen = len(newl)
print (newl)
if newl[i] == target:
print ("match found at ", i)
count += 1
i += 1
break
i += 1
print (count)
return count
When cannibal([27, 9, 3, 8, 11], 50) is given it returns IndexError: list index out of range and points to while newl[i] > newl [j] and j<listlen:

>>> cannibal([27, 9, 3, 8, 11], 50)
[27, 11, 9, 8, 3]
index is 0
list length is 5
27 is eating 11
[28, 9, 8, 3]
28 is eating 9
[29, 8, 3]
29 is eating 8
[30, 3]
30 is eating 3
[31]
Traceback (most recent call last):
File "<pyshell#169>", line 1, in <module>
cannibal([27, 9, 3, 8, 11], 50)
File "<pyshell#168>", line 36, in cannibal
while newl[i] > newl [j] and j<listlen:
IndexError: list index out of range
I ran the testcase you mentioned was failing. At first glance it looks like there is an improper exit condition. Upon further inspection, it seems like your innermost while loop is eventually forced to evaluate a condition that would raise an IndexError.
When I stick a print(newl, i, j) at the end of that while loop, here's what we get:
>>> cannibal([27, 9, 3, 8, 11], 50)
[27, 11, 9, 8, 3]
index is 0
list length is 5
27 is eating 11
[28, 9, 8, 3]
[28, 9, 8, 3] 0 1
28 is eating 9
[29, 8, 3]
[29, 8, 3] 0 1
29 is eating 8
[30, 3]
[30, 3] 0 1
30 is eating 3
[31]
[31] 0 1
Traceback (most recent call last):
File "<pyshell#175>", line 1, in <module>
cannibal([27, 9, 3, 8, 11], 50)
File "<pyshell#174>", line 37, in cannibal
while newl[i] > newl [j] and j<listlen:
IndexError: list index out of range
Hopefully now it's clear what the issue is.
At a point during that while loop, you end up with newl = [31], i = 0, and j = 1.
When the condition while newl[i] > newl [j] and j<listlen is evaluated, of course newl[0] > newl[1] is going to break the function because newl[1] doesn't exist.
To stop the error from happening, the easiest thing was to add a flag to break out of the for loop.
def cannibal(l, target):
newl = l
count = 0
i = 0
listlen = len(newl)
try:
newl = l.split(",")
newl.sort(reverse = True)
newl = list(map(int, newl))
print (newl)
except:
newl.sort(reverse = True)
print (newl)
finally:
while i < len(newl):
print ("index is ",i)
if newl[i] == target:
print ("match found at ", i)
count += 1
i += 1
continue
if newl[i] > target:
i += 1
continue
break_out = False
for j in range(i+1,listlen-1):
if break_out: break
print ("list length is",listlen)
while newl[i] > newl [j] and j<listlen:
print (newl[i]," is eating ",newl[i+1])
newl.remove(newl [i+1])
newl[i] = newl[i]+1
listlen = len(newl)
print (newl)
print(newl, i, j)
if newl[i] == target:
print ("match found at ", i)
count += 1
i += 1
print(newl, i, j)
break
if i >= len(newl) or j >= len(newl):
print ("loop is broken")
break_out = True
break
i += 1
print (count)
return count
However, I believe the problem goes a little deeper. I don't entirely understand how you intended this function to work but I have a hunch you don't want newl to become [31] permanently after the first iteration of your for loop.

Related

How can I print integers in one line inside the brackets (Fibonacci sequence with nth value)

Is it possible to print integers in one line inside the brackets? I would like my output to look like this:
[0 1 1 2 3 5 8 13 21 34]
But due to the way I wrote my code I can add brackets at the end of the list 0 1 1 2 3 5 8 13 21 34[] but not start and end.
My code:
n = int(input("Input a number to create Fibonacci sequence: "))
def fibo(n):
if n <=0:
print("Incorrect input")
return []
if n == 1:
return [0]
a,b = 0,1
for i in range(0,n):
print(a , end = " ",)
#assign a=b and b=a+b to get the sequence
a,b=b,a+b
print()
fibo(n)
The output format you are looking for is the one you get when you print a list.
You can use recursion to progressively build th eresulting list:
def fibo(n,a=0,b=1): return [a]+fibo(n-1,b,a+b) if n else [a]
print(fibo(10)) # fibonacci up to index 10
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
It can also be done iteratively
n = 10 # first 10 fibonacci numbers
fibo = [0,1]
while len(fibo) < n: fibo.append(sum(fibo[-2:]))
print(fibo[:n])
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

One excess element in the array is always left

I'm working on a validator of credit cards. That sphere is new for me, so please, don't laugh:D
I'm trying to finish it without any libraries.
def creditCardValidation(creditcard):
creditcard = creditcard.replace( ' ', '' )
creditcard = [int(i) for i in creditcard]
evens = creditcard[::2]
odds = creditcard[1::2]
evens = [element * 2 for element in evens]
for j in evens:
if j >= 10:
j = [int(d) for d in str(j)]
for x in j:
evens.append(x)
for j in evens:
if j >= 10:
evens.remove(j)
return ((sum(evens) + sum(odds)) % 10 == 0)
creditCardValidation('1234 5678 9101 1213')
creditCardValidation('4561 2612 1234 5464')
creditCardValidation('4561 2612 1234 5467')
So the problem is in the array evens.
It returns
[2, 6, 14, 0, 2, 2, 1, 0, 1, 4, 1, 8]
[8, 4, 2, 2, 6, 12, 1, 2, 1, 0, 1, 2]
[8, 4, 2, 2, 6, 12, 1, 2, 1, 0, 1, 2]
It should return the same results except those which greater than 10. Everything works fine. Take a look at the first array, 18 deleted as well as 10, but 14 is not.
Removing while iterating over the array is not the best thing to do and will mostly result in skipping some elements in the array while iterating, so a safer way to do this
for j in evens:
if j >= 10:
evens.remove(j)
is to collect all the elements you want to remove in another list then subtract it from your original if you are using numpy arrrays or removing them one by one, as python lists has no subtraction operation defined to subtract one array from a another
to_remove = []
for j in evens:
if j >= 10:
to_remove.append(j)
for j in to_remove:
events.remove(j)
or you could whitelist instead of blacklisting
small_evens = []
for j in evens:
if j < 10:
small_evens.append(j)
# use small_evens and discard evens array
A couple of issues:
Python has zero indexed arrays, so evens[::2] is actually returning the first, third, etc. digit. Luhn's algo requires even digits (assuming 1 indexing) to be doubled.
You shouldn't modify a list you are iterating over.
You can simplify, removing a lot of the list creations:
def creditCardValidation(creditcard):
*creditcard, checkdigit = creditcard.replace(' ', '')
total = 0
for i, digit in enumerate(map(int, creditcard), 1):
if i % 2 == 0:
digit *= 2
total += digit // 10 # Will be zero for single digits
total += digit % 10
return 9*total % 10 == int(checkdigit)
In []:
creditCardValidation('1234 5678 9101 1213')
Out[]:
True
In []:
creditCardValidation('4561 2612 1234 5464')
Out[]:
False

Two arrays sorted to see if they have the same value, but it only picks up that there are 2/3 values that are the same in the arrays

I don't know why only 2 out of 3 of values are showing that they are the same in my code, is there something I am missing?
def occurInBoth(B,A):
occured = 0
for i in range(len(A)):
if A[i] == B[i]:
occured += 1
return occured
A = [5,12,31,7,25]
sorted(A)
A.sort()
print(A)
B = [4,12,7,31,42,8]
sorted(B)
B.sort()
print(B)
occured = occurInBoth(B,A)
print(occured)
Could you please advise me?
There is a logical error in your algorithm. If two lists are sorted, that does not mean that the items will occur at the same index.
Indeed, take the sorted lists in your example:
A = [5, 7, 12, 25, 31]
B = [4, 7, 8, 12, 31, 42]
As you can see 12 occurs in both lists, but not at the same index.
You can however make use of the fact that the lists are sorted:
def occurInBoth(a, b):
occured = i = j = 0
while i < len(a) and j < len(b):
if a[i] < b[j]:
i += 1
elif a[i] > b[j]:
j += 1
else:
occurred += 1
i += 1
j += 1

Python recursive function for Pascal's Triangle

I'm trying to do a recursive function that generates a pascal's triangle up till the nth row, n being the user input. This is my code so far:
def printPascal(l,n):
while n != 1:
temp = [None]*(len(l)+1)
temp[0] = 1
temp[len(l)] = 1
for i in range(1,len(temp)-1):
temp[i] = l[i] + l[i-1]
l = temp
print(temp)
n = n-1
printPascal(l,n)
n = int(input("Enter a value for n:"))
l = [1,1]
printPascal(l,n)
And this is the error it gives me:
Traceback (most recent call last):
File "C:\Users\User\Desktop\test.py", line 16, in <module>
printPascal(l,n)
File "C:\Users\User\Desktop\test.py", line 11, in printPascal
printPascal(l,n)
File "C:\Users\User\Desktop\test.py", line 7, in printPascal
temp[i] = l[i] + l[i-1]
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
The thing is i kinda understand the issue and have tried tracing it to no avail. I know that somehow in the temp[i] = l[i] + l[i-1] code either the l[i] or l[i -1] is a "None" and i don't know why.
Thanks for your time and help in this little predicament of mine.
You have too much of your code inside the "for" loop. You replace the value of l with the value of temp before you've finished filling in all the values in temp.
The for loop should only contain the first statement.
There was a little indentation error in your code.
def printPascal(l,n):
while n != 1:
temp = [0]*(len(l)+1)
temp[0] = 1
temp[len(l)] = 1
for i in range(1,len(temp)-1):
temp[i] = l[i] + l[i-1]
l = temp
print(temp)
n = n-1
printPascal(l,n)
Instead of fixing your code, I'll show you an optimized approach:
def pascal_triangle(n, triangle=[[1]]):
if n > len(triangle):
last_row = triangle[-1]
next_row = [a+b for (a, b) in zip([0] + last_row, last_row + [0])]
return pascal_triangle(n, triangle + [next_row])
return triangle
How you can run it:
n = int(input("Pascal's triangle size: "))
print(*pascal_triangle(n), sep="\n")
Example output for input 9:
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
Or using a prettier printing command:
print(*[" ".join(map(str, line)).center(40) for line in pascal_triangle(9)], sep="\n")
It would look like this:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
See this code running on ideone.com
You get this error because you not calculate and you not return sufficient information to the function.
try to debug or to follow your code..
You will fined the problem easily :)

Python - Create a group of lists using numbers

say I have a string n = '22' and another number a = 4 so that n is a str and a is an int. I would like to create a group of lists like:
list1 = [22, 12, 2] #decreasing n by 10, the last item must be single digit, positive or 0
list2 = [22, 11, 0] #decreasing n by 11, last item must be single digit, positive or 0
list3 = [22, 21, 20] #decreasing n by 1, last item must have last digit 0
list4 = [22, 13] #decreasing n by 9, last item must be single digit. if last item is == a, remove from list
list5 = [22, 32] #increasing n by 10, last item must have first digit as a - 1
list6 = [22, 33] #increasing n by 11, last item must have first digit as a - 1
list7 = [22, 23] #increasing n by 1, last item must have last digit a - 1
list8 = [22, 31] #increasing n by 9, last item must have first digit a - 1
I am struggling on how to start this. Maybe you can give me an idea of how to approach this problem?
By the way if a condition cannot be satisfied, then only n will be on that list. say n = '20', a = 4:
list3 = [20]
Also this is for a school project, for indexes in a list which has list items. I can't think of a better way to approach the problem.
This should get you started:
def lbuild( start, inc, test ):
rslt = [start]
while not test(start,inc):
start += inc
rslt.append( start )
return rslt
n = '22'
a = 4
nval = int(n)
print lbuild( nval, -10, lambda(x,y): (x<10 and x>=0) )
print lbuild( nval, 1, lambda(x,y): x%10 == a-1 )

Categories

Resources