How to use append method in function? - python

def perfect(number):
lst = []
sum = 0
for i in range(1,number):
if number % i == 0:
lst.append(i)
sum += i
return sum == number
for k in range(1,1000):
if perfect(k):
print(k)
The code works well except one thing. It finds perfect numbers(ie: 6 = 1+2+3). However, I want to print those dividing numbers in a list(ie: Perfect Number:6, dividing numbers: [1,2,3]). I've tried to use append method but couldn't print it anyways.

Just insert your list and the input number as an output of function:
def perfect(number):
lst = []
sum = 0
for i in range(1,number):
if number % i == 0:
lst.append(i)
sum += i
return (sum == number, lst, number)
Then you can print it assign the list to any variable you want using unpacking:
(result, printList, nr) = perfect(6)
print(f"Perfect Number: {nr}, Dividing numbers: {printList}")
Output
Perfect Number: 6, Dividing numbers: [1, 2, 3]

You'll need to return the list:
def perfect(number):
lst = []
sum = 0
for i in range(1,number):
if number % i == 0:
lst.append(i)
sum += i
if sum == number:
return lst
else:
return False
# Now the function can return either a list or False
for k in range(1,1000):
if isinstance(perfect(k), list):
print(k)

See this solution
def perfect(number):
sum = 0
lst = []
for i in range(1,number):
if number % i == 0:
lst.append(i)
sum += i
return ((sum == number),lst)
for k in range(1,1000):
res,lst = perfect(k)
if res:
print("{:<4} {}".format(k ,lst) )
Output
6 [1, 2, 3]
28 [1, 2, 4, 7, 14]
496 [1, 2, 4, 8, 16, 31, 62, 124, 248]

Related

calculate the total number of odd elements in a list

arr=[13,15,4,6,8,71,45,54,56,77,67,88,49,33838,3784376,77735]
for num in arr:
if num % 2 != 0:
a = sum(num)
print(a)
Output:
TypeError: 'int' object is not iterable
The problem is due because "num" is just an element inside your list and sum functions needs to receive an iterable, if you just want to count the odd elements inside arr you can use:
If you want to count the odd elements
oddsCounter = len([x for x in arr if x % 2 != 0])
print(oddsCounter)
If you want to get the total sum
oddsSum = sum([x for x in arr if x % 2 != 0])
print(oddsSum)
You cannot call sum on an int (num). You can do the following:
arr = [13, 15, 4, 6, 8, 71, 45, 54, 56, 77, 67, 88, 49, 33838, 3784376, 77735]
count = 0
for num in arr:
if num % 2 != 0:
count += 1
print(count)
or more simply:
print(sum(num % 2 == 1 for num in arr))
You can do with list comprehension,
In [1]: sum([i for i in arr if i %2 != 0])
Out[1]: 78072
And, sum(int) is not possible because sum only takes iterable (list, tuple, etc.) as the argument.
sum only accepts iterables, not single items.
try this:
a = a + num
take a look at this link to learn more about sum.
You need to remove a = sum(num). sum() takes an array but you have given it a int.
The code should be like this:
total = 0
arr=[13,15,4,6,8,71,45,54,56,77,67,88,49,33838,3784376,77735]
for num in arr:
if num % 2 != 0:
total = total + 1
print(total)
You are looping over the list, thus num is the current element in the iteration. You want to use sum on an iterable such as below:
> arr = [13,15,4,6,8,71,45,54,56,77,67,88,49,33838,3784376,77735]
> sum(num % 2 == 0 for num in arr)
8
I think you can get them with a list comprehension:
arr=[13,15,4,6,8,71,45,54,56,77,67,88,49,33838,3784376,77735]
elems = sum([ 1 if num %2 != 0 else 0 for num in arr])
print(f"Number of odd elements: {elems}")
Checkout as you are trying to sum the value of the "num" itself. Not sure if you were trying to append it to a list onto a.
im no sure what you mean by total number of odd elements as in all the times theres a odd number or the sum of all the odd numbers but here
arr=[13,15,4,6,8,71,45,54,56,77,67,88,49,33838,3784376,77735]
a = 0
for num in arr:
if num % 2 != 0:
a += num
print(a)
sum is used on lists so if you realy wanted to use the sum it looks like this
arr=[13,15,4,6,8,71,45,54,56,77,67,88,49,33838,3784376,77735]
a = []
for num in arr:
if num % 2 != 0:
a.append(num)
print(sum(a))
try using modulo and list comprehension
arr=[13,15,4,6,8,71,45,54,56,77,67,88,49,33838,3784376,77735]
def odd_elements(arr):
return len([x for x in arr if x % 2 != 0])
print(odd_elements(arr))
or, using sum()
arr=[13,15,4,6,8,71,45,54,56,77,67,88,49,33838,3784376,77735]
def odd_elements(arr):
return sum(1 for i in arr if i % 2)
print(odd_elements(arr))

How to get the sum of a list of numbers excluding integers that are divisible by 3 and 7 with recursion?

I am trying to find the summation of integer in list with elements that are divisible by 3 or 7 excluded
def SumSkip37(numList,sum = 0):
if numList:
i = numList.pop()
if i % 3 == 0 or i % 7 == 0:
return sum
else:
sum += i
return SumSkip37(numList, sum=sum)
numList = [1, 3, 5, 7, 9]
print(f'The result is {SumSkip37(numList)}.')
Pls help me figure out
You can update your code to:
def SumSkip37(numList, my_sum = 0): # avoid using sum
if numList:
i = numList.pop()
if i % 3 == 0 or i % 7 == 0:
return SumSkip37(numList, my_sum=my_sum) # pass the unchanged sum
else:
return SumSkip37(numList, my_sum=my_sum+i) # pass the sum + i
else:
return my_sum
NB. I tried to stay as close as possible to the original, but you can simplify greatly!
To avoid mutating the input:
def SumSkip37(numList, my_sum = 0):
if numList:
if numList[0] % 3 != 0 and numList[0] % 7 != 0:
my_sum += numList[0]
return SumSkip37(numList[1:], my_sum=my_sum)
return my_sum
print(f'The result is {SumSkip37(numList)}.')
Better approach than the alternative above suggested by #Stef to run in linear time:
def SumSkip37(numList, my_sum=0, idx=0):
if idx >= len(numList):
return my_sum
elif numList[idx] % 3 != 0 and numList[idx] % 7 != 0:
return SumSkip37(numList, my_sum + numList[idx], idx + 1)
return SumSkip37(numList, my_sum, idx + 1)
Also, recursion is overkill here, better use a short generator expression:
sum(i for i in numList if i%7!=0 and i%3!=0)
You are on the right track. You just weren't iterating through the whole list:
def SumSkip37(numList, total=0):
if numList:
i = numList.pop()
if i % 3 != 0 and i % 7 != 0:
total += i
return SumSkip37(numList, total=total)
return total
I flipped the comparison to remove the unnecessary else branch. It doesn't matter if the current number is divisible with 3 or 7 or not, you always want to continue the recursion until the list runs out.
Without Recursive function:
def SumSkip37(list):
sum = 0
for i in list:
if i % 3 == 0 or i % 7 == 0:
continue
else:
sum += i
return sum
list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(SumSkip37(list))
With Recursive Function:
def SumSkip37(lst):
if len(lst) == 0:
return 0
else:
if lst[0] % 3 == 0 or lst[0] % 7 == 0:
return SumSkip37(lst[1:])
else:
return lst[0] + SumSkip37(lst[1:])
print(SumSkip37([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
On relatively clean way:
def SumSkip37(numList):
if not numList:
return 0
head, *tail = numList
return head * bool(head % 3 and head % 7) + SumSkip37(tail)

how to find the product of even numbers in a list using recursion?

I am trying to write function that takes a list of numbers and returns the product of even numbers using recursion. I have an idea of how it should be solved, but my problem is i don't get the right value.
This is my code
def prodotto_lista_pari (l):
if len(l) == 1:
return l[0]
n = 0
if l[n] % 2 == 0:
return prodotto_lista_pari([l[0]]) * prodotto_lista_pari(l[1:])
return prodotto_lista_pari(l[1:])
l = [2, 1, 5, 12, 80, 77, 15]
the output should be 1920
the ouput i get instead is 28800
Any help will be appreciated
def prodotto_lista_pari (l):
if len(l) == 1:
if l[0] % 2==0:
return l[0]
else:
return 1
n = 0
if l[n] % 2 == 0:
return prodotto_lista_pari([l[0]]) * prodotto_lista_pari(l[1:])
return prodotto_lista_pari(l[1:])
l = [2, 1, 5, 12, 80, 77, 15]
for the last element, you returned value without checking even or odd. So, you are getting
wrong result. So your output is lastelement *1920 =28800
I modified it a little:
def prodotto_lista_pari(l):
if not l: # Checks if list is empty
return 1
n = l[0]
if n % 2 == 0:
return n*prodotto_lista_pari(l[1:])
return prodotto_lista_pari(l[1:])
In general, you had a few issues:
You did not check if the last item is even.
You always made an extra call for no reason.
You had a seemingly unused variable n. I've used it for caching the first item as you can see.
You forgot to check if the base case is pair
def prodotto_lista_pari (l):
if len(l) == 1:
if l[0] % 2 == 0:
return l[0]
return 1
n = 0
if l[n] % 2 == 0:
return prodotto_lista_pari([l[0]]) * prodotto_lista_pari(l[1:])
return prodotto_lista_pari(l[1:])
l = [2, 1, 5, 12, 80, 77, 15]
print(prodotto_lista_pari(l))
>> 1920
What happens is that the last element 15 fall at base condition
So, you multiply 1920 by 15 which gets you 28800
By the way, your version rapidly reaches max recursion depth in python, a better version would break the list in halves so that you get log(n) recursion depth.
You need to check the base case for even/odd and take care to handle empty list as well. Also you can remove n to reference to the first item in the list (if that is the reason why you are using it)
Below is the code, which takes care of these:
def prodotto_lista_pari (l):
if len(l) == 1:
if l[0] % 2 ==0:
return l[0]
else:
return 1
if l[0] % 2 == 0:
return prodotto_lista_pari([l[0]]) * prodotto_lista_pari(l[1:])
return prodotto_lista_pari(l[1:])
l = [2, 1, 5, 12, 80, 77, 15]
print(prodotto_lista_pari(l))

Python sum of number in array, ignoring sections of specific numbers

I am very new to Python and have been going through multiple tutorials to get better.
I have straggled with one difficult problem and found a solution. But it feels, works very newbie like. I think that I have tailored it to answer the specific question.
So the question is:
SUMMER OF '69: Return the sum of the numbers in the array, except ignore sections of numbers starting with a 6 and extending to the next 9 (every 6 will be followed by at least one 9). Return 0 for no numbers.
summer_69([1, 3, 5]) --> 9
summer_69([4, 5, 6, 7, 8, 9]) --> 9
summer_69([2, 1, 6, 9, 11]) --> 14
My code to solve this is:
def summer_69(arr):
list1 = arr
summ = int()
for i in range(0, len(arr)):
if 6 in list1:
listOfRange = range(list1.index(6), list1.index(9) + 1)
for index in listOfRange:
print(listOfRange)
arr[index] = 0
if 6 != arr[i]:
summ += arr[i]
else:
continue
else:
summ += arr[i]
return summ
It is a very basic problem and I am very alerted that I have struggled with something like this already.
Short O(n) solution using an iterator and the in operator to search for (and thereby skip to) the 9 following each 6:
def summer_69(lst):
it = iter(lst)
return sum(x for x in it
if x != 6 or 9 not in it)
Less dense version:
def summer_69(lst):
it = iter(lst)
total = 0
for x in it:
if x == 6:
9 in it
else:
total += x
return total
Correctness check (random test cases) and benchmark (with [1] * 5000 + [6, 9] * 2500) along with the accepted answer's solution (which takes O(n2)):
30 out of 30 tests correct
303045 us 303714 us 304335 us 306007 us 309986 us summer_69_Accepted
444 us 446 us 464 us 478 us 527 us summer_69_Kelly1
442 us 448 us 453 us 465 us 500 us summer_69_Kelly2
Code (Try it online!):
from timeit import repeat
def summer_69_Accepted(lst):
copyoflist = lst[:] # makes shallow copy of list
while True:
if 6 not in copyoflist:
return sum(copyoflist)
indexof6 = copyoflist.index(6)
indexof9 = copyoflist.index(9, indexof6+1) # begin search for 9 after 6
del copyoflist[indexof6:indexof9+1]
def summer_69_Kelly1(lst):
it = iter(lst)
return sum(x for x in it
if x != 6 or 9 not in it)
def summer_69_Kelly2(lst):
it = iter(lst)
total = 0
for x in it:
if x == 6:
9 in it
else:
total += x
return total
funcs = summer_69_Accepted, summer_69_Kelly1, summer_69_Kelly2
from random import randrange, choices
def testcase():
def others():
return choices([0, 1, 2, 3, 4, 5, 7, 8], k=randrange(10))
lst = others()
for _ in range(10):
lst += [6, *others(), 9, *others()]
return lst
tests = correct = 0
for _ in range(10):
lst = testcase()
expect = funcs[0](lst.copy())
for func in funcs:
result = func(lst.copy())
correct += result == expect
tests += 1
print(correct, 'out of', tests, 'tests correct')
print()
lst = [1] * 5000 + [6, 9] * 2500
for func in funcs:
times = repeat(lambda: func(lst), number=1)
print(*('%6d us ' % (t * 1e6) for t in sorted(times)), func.__name__)
Here's how I'd do it, as a first cut:
def summer_69(series):
in_summer = False
cur_sum = 0
for v in series:
if in_summer:
if v == 9:
in_summer = False
else:
if v == 6:
in_summer = True
else:
cur_sum += v
return cur_sum
Here's a version that uses a more reusable pythonic idiom, a generator function, and is a little more compact (at the slight cost of an extra comparison):
def yield_non_summer(series):
in_summer = False
def stateful_summer_predicate(v):
nonlocal in_summer
if in_summer and v == 9:
in_summer = False
return True # 9 is still in summer
elif not in_summer and v == 6:
in_summer = True
return in_summer
return (v for v in series if not stateful_summer_predicate(v))
def summer_69(series):
return sum(yield_non_summer(series))
Or, in fewer lines:
def yield_non_summer(series):
in_summer = False
def stateful_summer_predicate(v):
nonlocal in_summer
in_summer = (in_summer or v == 6) and v != 9
return in_summer
return (v for v in series if not stateful_summer_predicate(v))
def summer_69(series):
return sum(yield_non_summer(series))
def summer_69(arr):
sum = 0
Flag = False
if 6 not in arr:
for num in arr:
sum = sum + num
return sum
else:
for num in arr:
if num != 6 and Flag == False:
sum = sum + num
elif num == 6:
Flag = True
continue
elif Flag == True and num != 9:
continue
elif num == 9:
Flag = False
return sum
A simple approach is to make a filter and sum the results.
Code
def filter_substring(seq, start, end):
"""Yield values outside a given substring."""
release = True
for x in seq:
if x == start:
release = False
elif x == end:
release = True
elif release:
yield x
def summer(seq):
"""Return the sum of certain values."""
return sum(filter_substring(seq, 6, 9))
Demo
assert 0 == summer([])
assert 6 == summer([1, 2, 3])
assert 6 == summer([1, 2, 3, 6, 8, 7, 9])
assert 9 == summer([1, 3, 5])
assert 8 == summer([3, 5, 6, 7, 8, 9])
assert 15 == summer([2, 1, 6, 9, 12])
assert 16 == summer([2, 1, 6, 9, 1, 6, 6, 120, 9, 9, 12])
Details
filter_substring()+
This is a generator function. It iterates the input sequence and only yields a value if the conditions are appropriate, i.e. when the release remains True.
>>> list(filter_substring("abcde", "c", "d"))
['a', 'b', 'e']
>>> list(filter_substring([0, 1, 2, 3, 10], 1, 3))
[0, 10]
summer()
Here we simply sum whatever filter_range() yields.
+Note: a substring is a contiguous subsequence; this may or may not include strings in Python.
Will work with indexes:
def summer_69(arr):
y = []
for x in arr:
if 6 in arr:
a = arr.index(6)
b = arr.index(9)
del arr[a:b+1]
y = arr
elif arr == []:
return "0"
else:
return sum(arr)
return sum(y)
print(summer_69([])) #0
print(summer_69([1, 3, 5])) #9
print(summer_69([4, 5, 6, 7, 8, 9])) #9
print(summer_69([2, 1, 6, 9, 11])) #14
print(summer_69([2, 1, 6, 9, 6, 11, 25, 36, 11, 9, 4, 6, 4, 6, 3, 9, 15])) #22
Something like this:
def summer_69(lst):
"""Return the sum of the numbers in the array,
except ignore sections of numbers starting with a 6 and extending to the next 9
(every 6 will be followed by at least one 9). Return 0 for no numbers
"""
if not lst:
return 0
else:
_sum = 0
active = True
for x in lst:
if active:
if x != 6:
_sum += x
else:
active = False
else:
if x == 9:
active = True
return _sum
print(summer_69([1, 3, 5]))
print(summer_69([4, 5, 6, 7, 8, 9]))
print(summer_69([2, 1, 6, 9, 11]))
output
9
9
14
def summer_69(arr):
if 6 in arr:
c=arr[arr.index(6):arr.index(9)+1]
for i in c:
arr.remove(i)
print(arr)
return sum(arr)
else:
return sum(arr)
summer_69([1,2,3,4,5,6,7,8,9,10,11,12])
This will work:
def summer_69(arr):
total = 0
add = True
for num in arr:
while add:
if num != 6:
total += num
break
else:
add = False
while not add:
if num != 9:
break
else:
add = True
break
return total
def summer_69(arr):
a = 0
for nums in arr:
if nums == 6:
for items in arr[arr.index(6):]:
a = a+ items
if items == 9:
break
return sum(arr)-a
def summer_69(arr):
x = arr.count(6)
y = arr.count(9)
# to decide number of iteration required for loop
z = min(x,y)
k = 0
while k < (z) :
m = arr.index(6)
n = arr.index(9)
del arr[m:(n+1)]
k = k + 1
print(arr)
return sum(arr)
This will work for summer_69 problem as well for filtering substring
def filter_substring(seq, start, end):
flag = False
for char in seq:
if char == start:
flag = True
continue
elif flag:
if char == end:
flag = False
else:
continue
else:
yield char
def summer_69(seq, start, end):
return sum(filter_substring(seq, start, end))
def print_substring(string, start, end):
return list(filter_substring(string, start, end))
Example ::
seq = [4, 5, 9, 6, 2, 9, 5, 6, 1, 9, 2]
print(summer_69(seq, start=6, end=9))
string = "abcdef"
print(print_substring(string, start='c', end='e'))
This is the probably best answer if you are a newbie. I have simplified it as much as i can. you only need to know enumerate, function, for loops , tuple unpacking,if/else statements and break function.So lets go straight to the answer.
def myfunc(a):
mylist=[]
sum1 = 0
for b,c in enumerate(a):
if c==6:
for d in a[:b]:
mylist.append(d)
for e,f in enumerate(a):
if f==9:
for j in a[e+1:]:
mylist.append(j)
for y in a:
if y==6:
break
else:
mylist.append(y)
for k in mylist:
sum1 = sum1+k
print(sum1)
myfunc([1,3,5])
For those interested, here is my solution for this problem:
def summer_69(arr):
skate = arr
guitar = []
for i in range(len(arr)):
if 6 in arr:
guitar = skate[skate.index(6):skate.index(9)+1]
return abs(sum(skate) - sum(guitar))
else:
return sum(skate)
Replace
list1.index(9)+1
by
list1.index(9,list1.index(6)+1)+1
in line 6.
This will start searching for a 9 after 6.
This is taken from a Udemy course.
Here is the official answer . . .
def summer_69(arr):
total = 0
add = True
for num in arr:
while add:
if num != 6:
total += num
break
else:
add = False
while not add:
if num != 9:
break
else:
add = True
break
return total
Jose Periera has this on Python 'zero to hero' course.
My own particular approach was this . . .
def summer_69(arr):
#first find out if 6 or 9 are in the list
if 6 in arr and 9 in arr:
#Then create a variable that stores the index location of the number 6
#and the number 9
sixer = arr.index(6)
niner = arr.index(9)
#now return the sum of the array minus the sum of the values between
#index of 6 and index of 9 inclusive (hence the plus 1)
#This way will ignore the case of a 9 appearring before a 6 too.
return sum(arr) - sum(arr[sixer:niner+1])
#Otherwise just return the sum of the array.
else:
return sum(arr)
Happy to accept criticism here. I'm learning Python myself and I'm undergoing an Msc in computer science and hoping to apply for jobs in the field soon, so your comments will help me :)
My approach was to sum the whole list and the part of the list that we want to ignore and subtract them at the end.
def summer_69(arr):
result=0
reduction =0
for i in range(0,len(arr)):
result+=arr[i]
if arr[i] == 6:
temp = arr[arr.index(6):arr.index(9)+1]
reduction = sum(temp)
return result - reduction
def summer69(a):
for z in a:
if z==6 and 9 in a:
x=a.index(6)
y=a.index(9)
del a[x:y+1]
t= sum(a)
else:
t=sum(a)
return t
Will always prefer short , clear and easy understandable solution.
def summer_69(arr):
if 9 in arr :
sum = 0
y = arr.index(9)
for i , l in enumerate(arr):
if l == 6:
del arr[i:y+1]
for i in range(len(arr)):
sum = sum + arr[i]
return sum
elif 9 not in arr:
sum = 0
for i in range(len(arr)):
sum = sum + arr[i]
return sum
def summer_69(mylist):
if 6 in mylist:
return sum(mylist) - sum(mylist[mylist.index(6):mylist.index(9)+1])
else:
return sum(mylist)
def summer_69(arr):
returner = []
if 6 and 9 in arr:
a = arr.index(6)
b = arr.index(9)
if a < b:
seq = arr[a:(b+1)]
for i in arr:
if i not in seq:
returner.append(i)
return (sum(returner))
elif a > b:
seq = arr[b:(a+1)]
for i in arr:
if i not in seq:
returner.append(i)
return (sum(returner))
elif 6 in arr:
a = arr.index(6)
seq = arr[a:]
for i in arr:
if i not in slicer:
returner.append(i)
return(sum(returner))
elif 9 in arr:
a = arr.index(9)
seq = arr[a:]
for i in arr:
if i not in slicer:
returner.append(i)
return(sum(returner))
elif arr == []:
return 0
else:
return (sum(arr))
Just learning Python too and this was what I came up with for it:
def myfunc(arr):
ignore_list = []
newlist = []
for i,v in enumerate(arr):
if v >= 6 and v <= 9:
ignore_list.append(i)
if i in ignore_list:
newlist.append(0)
else:
newlist.append(v)
return sum(newlist)

Need to find efficient method to find Strong number [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Written a program to find the find the Strong number
A number is considered to be a Strong number if sum of the factorial of its digits is equal to the number itself.
145 is a Strong number as 1! + 4! + 5! = 145.
Need to accept a list, find the Strong Number among the list and return a list of same
Ive tried :
def factorial(number):
if number == 0 or number == 1:
return 1
else :
return number * factorial(number - 1)
def find_strong_numbers(num_list):
sum = 0
ret_list = []
for i in num_list :
sum = 0
lst = list(map(int,list(str(i)))) #Converting the number into a list of numbers
for j in lst :
sum += factorial(j)
if sum == i :
ret_list.append(i)
return ret_list
num_list=[145,375,100,2,10]
strong_num_list=find_strong_numbers(num_list)
print(strong_num_list)
In the above example, I have created a list of the digits of the number and found its factorial.
But,
def factorial(number):
if number == 0 or number == 1:
return 1
else :
return number * factorial(number - 1)
def find_strong_numbers(num_list):
sum = 0
ret_list = []
for i in num_list :
sum = 0
lst = list(str(i)) #A List of Strings of the digits
for j in lst :
sum += factorial(int(j))
if sum == i :
ret_list.append(i)
return ret_list
num_list=[145,375,100,2,10]
strong_num_list=find_strong_numbers(num_list)
print(strong_num_list)
Ive created a list of Strings of Digits in the number
Converted the string to number when calling the factorial function.
This seems to be efficient for me as I need not to convert it into a map and then to int(less conversion)
Is this correct, is this efficient than the previous one or is there any far better optimised Code than this to find Strong Number.
You can simply memoize the factorial function to speed up the processing
from functools import lru_cache
#lru_cache(maxsize=128)
def factorial(number):
if number <= 1:
return 1
else:
return number * factorial(number - 1)
Also, you can use a generator to get the next digit like this
def get_next_digit(num):
while num:
yield num % 10
num //= 10
print(sum(factorial(digit) for digit in get_next_digit(145)))
This avoids creating an intermittent list of strings.
PS: These are minor optimisations which may not greatly improve the performance of the program.
Overall Code
from functools import lru_cache
#lru_cache(maxsize=128)
def factorial(number):
if number <= 1:
return 1
else:
return number * factorial(number - 1)
def get_next_digit(num):
while num:
yield num % 10
num //= 10
def is_strong_number(num):
return sum(factorial(digit) for digit in get_next_digit(num)) == num
def find_strong_numbers(num_list):
return [num for num in num_list if is_strong_number(num)]
num_list = [145, 375, 100, 2, 10]
print(find_strong_numbers(num_list))
Since you're only using factorials of 0..9, there's no need to have a function to compute them, let alone a recursive one. You can just hardcode all 10 values:
facts = {'0': 1, '1': 1, '2': 2, '3': 6, '4': 24, '5': 120, '6': 720, '7': 5040, '8': 40320, '9': 362880}
and then simply use:
def is_strong(n):
return sum(facts[s] for s in str(n)) == n
You can squeeze a bit more cycles of out this by avoiding a string conversion:
facts2 = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
def is_strong2(n):
s, k = 0, n
while k:
s += facts2[k % 10]
k //= 10
return s == n
...but given the fact that it's proven there are no such numbers beside 1, 2, 145, 40585, the whole enterprise looks a bit pointless ;)
Another version, using builtin math.factorial (doc):
from math import factorial
def is_strong_number(num):
return num == sum(factorial(int(c)) for c in str(num))
num_list=[145,375,100,2,10]
strong_num_list = [num for num in num_list if is_strong_number(num)]
print(strong_num_list)
Prints:
[145, 2]
others have already suggested improvements in their answers,
just for the sake of demonstrating a more empirical approach to runtime benchmarking:
you can use timeit to compare the runtime of different functions.
I added both of yours, and also a version that doesn't do the string<->int casting at all.
import timeit
def factorial(number):
if number == 0 or number == 1:
return 1
else:
return number * factorial(number - 1)
def find_strong_numbers_with_map(num_list):
sum = 0
ret_list = []
for i in num_list:
sum = 0
lst = list(map(int, list(str(i)))) # Converting the number into a list of numbers
for j in lst:
sum += factorial(j)
if sum == i:
ret_list.append(i)
return ret_list
def find_strong_numbers_cast_on_call(num_list):
sum = 0
ret_list = []
for i in num_list:
sum = 0
lst = list(str(i)) # A List of Strings of the digits
for j in lst:
sum += factorial(int(j))
if sum == i:
ret_list.append(i)
return ret_list
def find_strong_numbers_by_div_mod(num_list):
sum = 0
ret_list = []
for i in num_list:
sum = 0
while i > 0:
j = i % 10 # get the value of the last digit
sum += factorial(int(j))
i = i // 10 # "cut" the last digit from i
if sum == i:
ret_list.append(i)
return ret_list
num_list = [*range(1, 1000)]
print(timeit.timeit(lambda: find_strong_numbers_with_map(num_list), number=10 ** 3))
print(timeit.timeit(lambda: find_strong_numbers_cast_on_call(num_list), number=10 ** 3))
print(timeit.timeit(lambda: find_strong_numbers_by_div_mod(num_list), number=10 ** 3))
results on my laptop are:
2.4222552359969995
2.114583875001699
1.8628507399989758
There are several things you can do.
The first thing that comes to mind is making the factorial function iterative, instead of recursive:
def factorial(number):
if number == 0 or number == 1:
return 1
result = 1
for i in range(number + 1):
result *= i
return result
The second one would be to precompute all factorials for each digit, since there is a limited amount of them:
def get_factorials():
result = [1, 1]
value = 1
for i in range(2, 10):
value *= i
result.append(value)
return result
Then, instead of calling factorial each time, you could just do:
factorials = get_factorials()
lst = list(str(i))
for j in lst :
sum += factorials[int(j)]
Your result function could then be as simple as:
def is_strong_number(num):
return num == sum(map(lambda x: factorials[int(x)], str(num))
def find_strong_numbers(nums):
factorials = get_factorials()
return [num for num in nums if is_strong_number(num)]
Edit: thanks khelwood, fixed :)

Categories