A Rule of Divisibility by 13 - Codewars python challenge (RecursionError) - python-3.x

Instructions:
When you divide the successive powers of 10 by 13 you get the following remainders of the integer divisions:
1, 10, 9, 12, 3, 4.
Then the whole pattern repeats.
Hence the following method: Multiply the right most digit of the number with the left most number in the sequence shown above, the second right most digit to the second left most digit of the number in the sequence. The cycle goes on and you sum all these products. Repeat this process until the sequence of sums is stationary.
...........................................................................
Example: What is the remainder when 1234567 is divided by 13?
7×1 + 6×10 + 5×9 + 4×12 + 3×3 + 2×4 + 1×1 = 178
We repeat the process with 178:
8x1 + 7x10 + 1x9 = 87
and again with 87:
7x1 + 8x10 = 87
...........................................................................
From now on the sequence is stationary and the remainder of 1234567 by 13 is the same as the remainder of 87 by 13: 9
Call thirt the function which processes this sequence of operations on an integer n (>=0). thirt will return the stationary number.
thirt(1234567) calculates 178, then 87, then 87 and returns 87.
thirt(321) calculates 48, 48 and returns 48
My Code:
def thirt(n):
a = []
n = [int(i) for i in list(str(n))][::-1]
l = [1, 10, 9, 12, 3, 4][:len(n)]
y = sum([a * b for a,b in zip(n,l)])
a.append(y)
for c in a:
if a.count(c) == 1:
thirt(c)
else:
return c
thirt(5634)
When I run this I get an error
Traceback (most recent call last):
File "main.py", line 5, in <module>
Test.assert_equals(thirt(8529), 79)
File "/home/codewarrior/solution.py", line 9, in thirt
thirt(i)
File "/home/codewarrior/solution.py", line 9, in thirt
thirt(i)
File "/home/codewarrior/solution.py", line 9, in thirt
thirt(i)
[Previous line repeated 994 more times]
File "/home/codewarrior/solution.py", line 3, in thirt
n = [int(i) for i in list(str(n))][::-1]
RecursionError: maximum recursion depth exceeded while getting the str of an object
when I remove some part of the code and leave it like
def thirt(n):
n = [int(i) for i in list(str(n))][::-1]
l = [1, 10, 9, 12, 3, 4][:len(n)]
y = sum([a * b for a,b in zip(n,l)])
return y
thirt(5634)
I get 148 in the output, and then I thirt(148), I get 57, which is the desired answer, same goes for other examples as well.
so I just need a proper way to recur this function, and I just want it to stop as soon as the values start repeating, i.e. I want the loop of recursion to break as soon as I get two 57's in a row, and then I need it to return 57.
But I can't figure out a proper way to do it, because this is the first time I've applied recursion in a function, my code is really messed up, I'll really appreciate any help.

You are getting the error depth exceeded while getting the str of an object because you are assigning the list of digits n to the same variable name as the function parameter n. That means after the first recursive call, you are running [int(i) for i in list(str(n))][::-1] on a list of individual digits, and then a list of lists, and so on, rather than a single input number as you're expecting.
Once you fix that, you run into the issue of how you are checking for whether to make the recursive call:
a = []
a.append(y)
for c in a:
if a.count(c) == 1:
thirt(c)
I can see what you're trying to do, and it will not work in recursion because every time the function is called, a is reset to an empty list. That means a.count(c) == 1 is always true, and your function will go into an infinite recursive loop.
Instead, for this algorithm all you need to do is check whether your newly calculated y is equal to the number n that was passed to the function. If they're the same, that means you've gotten the same number twice in a row, so the algorithm is done.
After that is fixed, it will look like you're getting somewhere. You can use this logic:
if n != y:
thirt(y)
else:
print(y) # expected answer outputted to console
return y
Except when you call thirt(1234567), the value returned is None ! What the heck? I printed y and it's correct, it's right there! What is happening is, the inner-most call to thirt is returning the number you need, but then the next level up in the function call stack doesn't do anything with it. So the function ends and returns None. To fix this, you need each level of the recursive call to pass its return value up the chain. So use return thirt(y) instead of just thirt(y).
Finally, you need to account for the case when the number passed to the function is longer than 6 digits. Your l list needs to repeat in a cycle, not stop with the 6 numbers you've listed. You can get the list to be the length you need by multiplying it by the length of n divided by six, rounded up whenever there's a remainder.
After all that, you'll end up with something like the following:
def thirt(n):
nList = [int(i) for i in list(str(n))][::-1]
remainders = [1, 10, 9, 12, 3, 4] * (
len(nList) // 6 + min(1, len(nList) % 6)
)
y = sum([a * b for a,b in zip(nList,remainders)])
if n != y:
return thirt(y)
else:
return y
print(thirt(1234567)) #87

Isn't this what you mean?
def thirt(n_raw):
a = []
n = [int(i) for i in list(str(n_raw))][::-1]
l = [1, 10, 9, 12, 3, 4]*(len(n)//6+1)
y = sum([a * b for a,b in zip(n,l)])
if(y==n_raw): return y
else: return thirt(y)
I think you just went in a very wrong direction with the second half of your function, but I might misunderstood the premise behind...

Related

Sieve of Eratosthenes with nested for loops

This is a very simple question about python. I was trying to get a list of prime numbers so I tried
primes = [2]
for i in primes:
for j in range(50):
if j%i != 0:
primes.append(j)
print(primes)
But it just goes into an indefinite loop.
You are looping over a list and appending to it that will make that infinite process as the iteration just takes the index but you can put an end by defining the limit value
There are lots of methods to achieve that, but i would suggest to just break if the number is bigger than the limit:
primes = [2]
limit = 40
for i in primes:
if primes[-1]>limit:break
for j in range(50):
if j%i != 0:
primes.append(j)
print(primes)
Before that, you should know what you are doing, an advice is to first do your calculations on paper and then code them.
Your code provides different results as they are not prime, first come up with an algorithm or search online.
using the provided algorithm you should be able to use the pseudocode to come up with one on your own, here is an example:
from math import isqrt
limit = 40
primes = [True]*limit
primes[0] = False
primes[1] = False
for i in range(2,isqrt(limit-1)+1):
if primes[i]:
for j in range(i*i,limit,i):
primes[j] = False
from numpy import where
print(list(where(primes)[0]))
# >>> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]

See if index is contained within a slice object

I have an enum like this:
class AgeCategory(Enum):
Child = slice(None, 16)
YoungAdult = slice(16, 25)
...
Old = slice(85, None)
It basically provides a range of ages (in years) which go in each category.
I would like a function to check which age range a certain value corresponds to. This was my idea:
def get_category(age: int) -> AgeCategory:
for age_range in AgeCategory:
if age in age_range.value #check if it's in the slice for that enum
return age_range
else:
assert False, "unreachable"
However assert 5 in slice(1,10) fails. OFC I could do something like:
s: slice = age_range.value
if s.start <= age < s.stop: #bounds check
return age_range
But that ignores the step argument and feels like reinventing the wheel a bit.
What's a pythonic way to express these age ranges? They are used as slices like this:
ya_data = np.sum(some_data[AgeCategory.YoungAdult])
In your case it is not so much important, but this should be faster than iterating when working with large slices:
a_slice = slice(4, 15, 3)
def is_in_slice(a_slice, idx):
if idx < a_slice.start or idx >= a_slice.stop:
return False
step = a_slice.step if a_slice.step else 1
if (idx - a_slice.start) % step == 0:
return True
else:
return False
test_array = np.where([is_in_slice(a_slice, idx) for idx in range(20)])[0]
print(test_array)
[ 4 7 10 13]
And test for very big slice:
a_big_slice = slice(0, 1_000_000_000_000, 5)
print(is_in_slice(a_big_slice, 999_000_000_005))
print(is_in_slice(a_big_slice, 999_000_000_004))
True
False
With a sample slice:
In [321]: child=slice(None,16,4)
I was thinking of expanding it to a list or array. But arange can't handle the None:
In [323]: np.arange(child.start,child.stop,child.step)
Traceback (most recent call last):
File "<ipython-input-323-b2d245f287ff>", line 1, in <module>
np.arange(child.start,child.stop,child.step)
TypeError: unsupported operand type(s) for -: 'int' and 'NoneType'
np.r_ can. Here the numpy developers have gone to all the work of translating all the slice options:
In [324]: np.r_[child]
Out[324]: array([ 0, 4, 8, 12])
In [325]: 3 in _
Out[325]: False
In [327]: 4 in __
Out[327]: True
It may not be fastest, but appears to be most general purpose approach - with out a lot work on your part.

Finding number is present in sequence

I need to find out whether a given number is present in a given sequence. Sequence is an arithmetic progression with common difference of 2
Ex Input1 - 5, 7, 9, 11, 13, 15, . . .
for this sequence key is 19 so it is present i the sequence output would be True.
For input2 - be 4,6,8,10...
Given key is 15 so it is not present output should be False.
I have written the code but it is only working for first set of input which is odd numbers .Its failing for input2 which is even
arr = 4,6,8
n=10
b=max(arr)
l=[]
if b>n:
c=b
else:
c=n
d=arr[1]-arr[0]
for i in range(1,c+d+1,d):
l.append(i)
if n in l:
print("True")
else:
print("False")
Output 1 - True
output2 - False
You can take advantage of range's smart implementation of __contains__ to get a one-liner O(1) solution:
print(6 in range(2, 10, 2))
# True
print(5 in range(2, 10, 2))
# False
And an extreme example to show how fast and scalable this is (the size of the range does not matter):
from timeit import Timer
print(min(Timer(lambda: 1_000_000_000 in range(2, 1_000_000_003, 2)).repeat(1000, 1000)))
# 00032309999999990957

Optimising a fibonacci sequence generator python

I am trying to create a program which creates a Fibonacci sequence up to the value of the sequence being 200. I have the basic set up down where I can compute the sequence but I wish to display it in a certain way and I have forgotten how to achieve this.
I wish to write the numbers to an array which I have defined as empty initially, compute the numbers and assign them to the array and print said array. In my code below the computation is ok but when printed to screen, the array shows the value 233 which is above 200 and not what I'm looking for. I wish to print all the values under 200 which I've stored in an array.
Is there a better way to initially define the array for what I want and what is the correct way to print the array at the end with all elements below 200?
Code follows:
#This program calculates the fibonacci sequence up to the value of 200
import numpy as np
x = np.empty(14, float) #Ideally creates an empty array to deposit the fibonacci numbers in
f = 0.0 #Dummy variable to be edited in the while loop
#Here the first two values of the sequence are defined alongside a counter starting at i = 1
x[0] = 0.0
x[1] = 1.0
i = 1
#While loop which computes the values and writes them to the array x
while f <= 200:
f = x[i]+x[i-1] #calculates the sequence element
i += 1 #Increases the iteration counter by 1 for each loop
x[i] = f #set the array element equal to the calculated sequence number
print(x)
For reference here is a quick terminal output, Ideally I wish to remove the last element:
[ 0. 1. 1. 2. 3. 5. 8. 13. 21. 34. 55. 89.
144. 233.]
There are a number of stylistic points here. Firstly, you should probably use integers, rather than floats. Secondly, you should simply append each number to a list, rather than pre-define an array of a particular size.
Here's an interactive session:
>>> a=[0,1]
>>> while True:
b=a[-1]+a[-2]
if b<=200:
a.append(b)
else:
break
>>> a
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
Here is a way without using indices:
a = 0
x = [a]
b = 1
while b <= 200:
x.append(b)
a, b = b, a+b
print(x)

The error message TypeError: 'int' object does not support item assignment

factor = int(input("Which table would you like: "))
timestable = ([0,0])
for count in range(1,13):
timestable.append([0,0])
result = factor * count
timestable[count][0] = count
timestable [count][1] = result
for row in timestable:
print(row)
This is a program that allows a user to enter in a times table and prints out 1 * the number to 12 * the number. But whenever I go to run the code, I get this error message:
timestable[count][0] = count
TypeError: 'int' object does not support item assignment
Does anyone know what I have to change in my code?
As noted in comments, the problem is that the line timestable = ([0,0]) initializes timestable as just [0, 0]. Thus, after your first append, timestable looks like this: [0, 0, [0, 0]] instead of [[0, 0], [0, 0]], and the value behind timestable[count] is not the newly appended [0,0] but just the second 0 from initialization.
Maybe you wanted to create a one-tuple holding a list, but then you'd have to use ([0,0],) (note the trailing comma), but this won't do you any good, either, as you can not append to tuples. Instead, you should initialize it as a nested list. Also, you can shorten the body of the loop by not first appending zeros and then overwriting those zeros, but appending the correct values directly.
timestable = [[0,0]]
for count in range(1, 13):
timestable.append([count, factor * count])
However, you do not need the separate initialization and loop at all; you an just create timestable in a single list comprehension (note that here, the range starts from 0):
timestable = [[count, factor * count] for count in range(0, 13)]

Resources