I am trying to make my python program as optimised as possible, and there is this portion I am unsure about. I need to store the largest value obtained so far, and I have 2 candidate codes to do so. Which one is the most time-optimised? Or is there a faster way to do so?
Code 1:
if value > biggest_value:
biggest_value = value
Code 2:
biggest_value = max(biggest_value, value)
Context:
def check_palindrome(num):
num = str(num)
if len(num) < 1:
return True
else:
if num[0] == num[-1]:
return check_palindrome(num[1:-1])
else:
return False
def main():
biggest_product = 0
for a in range(100, 1000):
for b in range(100, 1000):
product = a * b
if check_palindrome(product):
# store the biggest_product here
return biggest_product
main()
Code 2 is the better option because in Code 1 you have to compare the numbers with 2 commands ( < = ) and in Code 2 you only have one command.
Good Luck with your Programm and have fun!
Jonas
Related
I am just starting to learn python and made a program where it calculates the factorial number based on the factorial.
For example if I give the program the number 120 it will tell me it's factorial is 5
anyways my question is how can I make this code more efficient and faster.
Num = int(input())
i=0
for i in range(0,Num):
i = i + 1
x = Num/i
Num = x
if (x==1):
print(i)
Multiplications are much faster than divisions. You should try to reach the number with a factorial instead of dividing it iteratively:
def unfactorial(n):
f,i = 1,1
while f < n:
i += 1
f *= i
return i if f == n else None
unfactorial(120) # 5
A few things you can do:
Num = int(input())
i=0 # your for loop will initialize i, you don't need to do this here
for i in range(0,Num):
i = i + 1 # your for loop will increment i, no need to do this either
x = Num/i # you don't need the extra variable 'x' here
Num = x
if (x==1):
print(i)
You can rewrite this to look something like:
for index in range(1, number): # start range at 1
number /= index # this means; number = number / index
if number==1:
return index
Compute the factorials in ascending order until you reach (or exceed) the factorial you are looking for, using the previous factorial to efficiently compute the next.
def reverse_factorial(num):
i = 1
while num > 1:
i += 1
num /= i
return i
print(reverse_factorial(int(input())))
I made myself an exercise with python since I am new. I wanted to make a rever LMC calculator ( Least common multiple ) but for some reason, something as simple as a print in a loop doesn't seem o work for me. I would appreciate some help since I am stuck on this weird issue for 20 minutes now. Here is the code:
import random
import sys
def print_list():
count_4_print = 0
while count_4_print < len(values):
print(values[count_4_print])
count_4_print += 1
def lcm(x, y):
if x > y:
greater = x
else:
greater = y
while True:
if (greater % x == 0) and (greater % y == 0):
lcm1 = greater
break
greater += 1
return lcm1
def guess(index, first_guess, second_guess):
num = 1
while lcm(first_guess, second_guess) != values[num - 1]:
first_guess = random.randrange(1, 1000000)
second_guess = random.randrange(1, 1000000)
num += 1
num = 1
if lcm(first_guess, second_guess) == values[num - 1]:
return first_guess, second_guess
num += 1
lineN = int(input())
values = []
count_4_add = 0
count_4_guess = 0
for x in range(lineN):
values.append(int(input()))
count_4_add += 1
if count_4_add >= lineN:
break
print_list()
for x in range(lineN + 1):
first, second = guess(count_4_guess, 1, 1)
count_4_guess += 1
print(first + second)
# this ^^^ doesn't work for some reason
Line 57 is in the while loop with count_4_guess. Right above this text, it says print(first_guess + second_guess)
Edit: The code is supposed to take in an int x and then prompt for x values. The outputs are the inputs without x and LMC(output1, output2) where the "LMC" is one of the values. This is done for each of the values, x times. What it actually does is just the first part. It takes the x and prompts for x outputs and then prints them but doesn't process the data (or it just doesn't print it)
Note: From looking at your comments and edits it seems that you are lacking some basic knowledge and/or understanding of things. I strongly encourage you to study more programming, computer science and python before attempting to create entire programs like this.
It is tough to answer your question properly since many aspects are unclear, so I will update my answer to reflect any relevant changes in your post.
Now, onto my answer. First, I will go over some of your code and attempt to give feedback on what could improved. Then, I will present two ways to compute the least common multiple (LCM) in python.
Code review
Code:
def print_list():
count_4_print = 0
while count_4_print < len(values):
print(values[count_4_print])
count_4_print += 1
Notes:
Where are the parameters? It was already mentioned in a few comments, but the importance of this cannot be stressed enough! (see the note at the beginning of my comment)
It appears that you are trying to print each element of a list on a new line. You can do that with print(*my_list, sep='\n').
That while loop is not how you should iterate over the elements of a list. Instead, use a for loop: for element in (my_list):.
Code:
def lcm(x, y):
if x > y:
greater = x
else:
greater = y
while True:
if (greater % x == 0) and (greater % y == 0):
lcm1 = greater
break
greater += 1
return lcm1
Notes:
This is not a correct algorithm for the LCM, since it crashes when both numbers are 0.
The comparison of a and b can be replaced with greater = max(x, y).
See the solution I posted below for a different way of writing this same algorithm.
Code:
def guess(index, first_guess, second_guess):
num = 1
while lcm(first_guess, second_guess) != values[num - 1]:
first_guess = random.randrange(1, 1000000)
second_guess = random.randrange(1, 1000000)
num += 1
num = 1
if lcm(first_guess, second_guess) == values[num - 1]:
return first_guess, second_guess
num += 1
Notes:
The line num += 1 comes immediately after return first_guess, second_guess, which means it is never executed. Somehow the mistakes cancel each other out since, as far as I can tell, it wouldn't do anything anyway if it were executed.
if lcm(first_guess, second_guess) == values[num - 1]: is completely redundant, since the while loop above checks the exact same condition.
In fact, not only is it redundant it is also fundamentally broken, as mentioned in this comment by user b_c.
Unfortunately I cannot say much more on this function since it is too difficult for me to understand its purpose.
Code:
lineN = int(input())
values = []
count_4_add = 0
count_4_guess = 0
for x in range(lineN):
values.append(int(input()))
count_4_add += 1
if count_4_add >= lineN:
break
print_list()
Notes:
As explained previously, print_list() should not be a thing.
lineN should be changed to line_n, or even better, something like num_in_vals.
count_4_add will always be equal to lineN at the end of your for loop.
Building on the previous point, the check if count_4_add >= lineN is useless.
In conclusion, count_4_add and count_4_guess are completely unnecessary and detrimental to the program.
The for loop produces values in the variable x which is never used. You can replace an unused variable with _: for _ in range(10):.
Since your input code is simple you could probably get away with something like in_vals = [int(input(f'Enter value number {i}: ')) for i in range(1, num_in_vals+1)]. Again, this depends on what it is you're actually trying to do.
LCM Implementations
According to the Wikipedia article referenced earlier, the best way to calculate the LCM is using the greatest common denominator.
import math
def lcm(a: int, b: int) -> int:
if a == b:
res = a
else:
res = abs(a * b) // math.gcd(a, b)
return res
This second method is one possible brute force solution, which is similar to how the one you are currently using should be written.
def lcm(a, b):
if a == b:
res = a
else:
max_mult = a * b
res = max_mult
great = max(a, b)
small = min(a, b)
for i in range(great, max_mult, great):
if i % small == 0:
res = i
break
return res
This final method works for any number of inputs.
import math
import functools
def lcm_simp(a: int, b: int) -> int:
if a == b:
res = a
else:
res = abs(a * b) // math.gcd(a, b)
return res
def lcm(*args: int) -> int:
return functools.reduce(lcm_simp, args)
Oof, that ended up being way longer than I expected. Anyway, let me know if anything is unclear, if I've made a mistake, or if you have any further questions! :)
Just playing with some basic code (factorials) but cannot quite get my head around how this is achieving the correct result. The result on each loop does not seem to be stored anywhere - so how does the code remember the iterated value? (I know there are modules - this is just a logic exercise)
def factoral2(num):
if num == 0:
return 1
return num * factoral2(num - 1)
Above is the method that I'm not quite sure how works
def factoral(num):
number = []
for i in range(0, num):
number.append(num)
num -= 1
print(number)
product = 1
for x in number:
product *= x
return product
This was my interpretation of its logic, which is obviously a bit more verbose than what's ideal
Both work - just trying to understand the logic of the optimised version
ok, let's run through an example lets say the user inputs 2 -> num=2.
First, we have to build our way down (essentially we need num to equal 0)
first, we call factorial(2), and check the if statement which turns out to be false.
therefor factorial(2) = return num * factorial(num-1) = return 2 * factorial(1)
the above statement needs to compute the value for factorial(1) before it can return a value, so let's go ahead and do that
first, we call factorial(1), and check the if statement which == false
therefor factorial(1) = return num * factorial(num-1) = return 1* factorial(0)
the above statement needs to compute the value for factorial(0) before it can return a value, so let's go ahead and do that also
first, we call factorial(0), and check the if statement which == true
therefor factorial(0) = 1
Now we can start building up
factorial(0) = 1
now just start plugging in values
we said factorial(1) = return 1* factorial(0) = return 1* 1 = return 1
factorial(1) = 1
now we can plug in some more values
we said factorial(2) = return 2* factorial(1) = return 2 * 1 = return 2
factorial(2) = 2
Thanks to Andreas and below_avg_st for your help.
Makes alot more sense now.
As I see it:
Recursive functions generate an infinite loop if a condition to break is not allocated.
(I've re-written the below to state that logic abit more). If X does not equal 0, keep looping through the function while decrementing X.
When the loop does break - (because X = 0) assign a value of 1 - to exit the loop.
def test(x):
if x != 0:
return x * test(x-1)
else:
return 1
test(4)
Thanks to all for your help
It's a recursive function that calls itself, giving num - 1 as argument.
The function supplied:
def factoral2(num):
if num == 0:
return 1
return num * factoral2(num-1)
"gets expanded" into this:
def factoral2(num):
result = 1
while (num != 0):
result *= num
num -= 1
return result
value = factoral2(4) can be illustrated as such:
num = 4
num = 3
num = 2
num = 1
num = 0; return 1
result = 1
result = 2 * 1
result = 3 * 2
result = 4 * 6
value = 24
I'd also like to note out a better non-recursive version of the factorial function, compared to the one you crafted, that unnecessarily creates and fills a list.
def factorial(n):
if n < 0:
raise ValueError("The factorial value may only be calculated on positive integers")
product = 1
for i in range(2, n + 1):
product *= i
return product
– or just a simplified recursive one, using the "ternary operator":
def factorial(n):
if n < 0:
raise ValueError("The factorial value may only be calculated on positive integers")
return 1 if n == 0 else n * factorial(n - 1)
not really familiar with while loops but I thought it was an alternative so this may be an elementary mistake.
I need to look for the sum of natural numbers under 1000 that are multiples of 3 and 5. E.g for under 10
multiples of 3 and 5 < 10 = 3,5,6,9
sum = 23
My code using a for loop works and is as follows (this was my initial solution):
def multiple():
lst = []
for x in range(334): #didn't know how else to use a for loop but to find the largest value of x using a calculator
if 3*x < limit:
lst.append(3*x)
if 5*x< 1000:
lst.append(5*x)
if (3*x > 1000) and (5*x > 1000): #unnecessary in a forloop with a range but this is just to maintain symmetry with while loop
break
lst2 = list(set(lst)) #remove duplicates
print(sum(lst2))
multiple()
My code using a while loop(this solution doesn't even come out in te console --> maybe this is were the error lies):
def multiple():
lst = []
while True:
x = 1
if 3*x < 1000:
lst.append(3*x)
if 5*x< 1000:
lst.append(5*x)
if (3*x > 1000) and (5*x > 1000):
break
x += 1
lst2 = list(set(lst)) #remove duplicates
print(sum(lst2))
multiple()
Desired output:
233168
In addition to how to rectify the while loop, any improvements on my for loop or while loop would also be welcome. Thanks
Critically Debugging
Since you're new, let's take this opportunity to analyze the bug before we solve it. Note first that you did not notice any printouts at all. Therefore, your print() statement was either not running, or was printing only spaces. We can rule out the latter since sum() will return an integer.
Therefore, the print() is never run. The function is defined and called correctly, so that's not the issue. Now notice while True:; this is an early warning sign. If the while loop never ends, the print() will never run. We do notice there are multiple break statements that should stop the loop, but it's likely there's an issue with them.
Now we check how the loop updates. First, note the i+=1. That seems right. However, i=1 is also within the while loop. This cannot be correct, since every iteration i will be reset. This would cause the loop to run forever.
This type of critical analysis of code is only built through practice, but hopefully this answer offers some insight into how you could have fixed this issue yourself (and how I looked through your code).
Also note that adding print statements into the while loop to test would have allowed you to notice that i was always 1.
Working Code
def multiple():
lst = []
x = 1 # moved from line below
while True:
# x = 1 should not go here
if 3*x < 1000:
lst.append(3*x)
if 5*x< 1000:
lst.append(5*x)
if (3*x > 1000) and (5*x > 1000):
break
x += 1
lst2 = list(set(lst)) #remove duplicates
print(sum(lst2))
multiple()
A fairly straight forward approach is to iterate over every number from 1 to 1000 and check if it is divisible by 3 or 5, and then sum them all up.
total = sum(x for x in range(1, 1001) if x%3 == 0 or x%5 == 0)
total
# returns:
234168
Another solution:
Using for loop:
def multiple():
sum = 0
for _ in xrange(1, 1001):
if _ % 3 == 0 or _ % 5 == 0:
sum += _
return sum
print(multiple())
Using while loop:
def multiple():
sum = 0
cnt = 1
while cnt <= 1000:
if cnt % 3 == 0 or cnt % 5 == 0:
sum += cnt
cnt += 1
return sum
print(multiple())
output:
234168
#!/usr/bin/env python
def multiple():
lst = []
x=1
while (3*x < 1000) or (5*x < 1000):
if 3*x < 1000:
lst.append(3*x)
if 5*x < 1000:
lst.append(5*x)
x += 1
lst2 = list(set(lst)) #remove duplicates
print(sum(lst2))
multiple()
def is_prime(x):
count = 1
my_list = []
while count > 0 and count < x:
if x % count == 0:
my_list.append(x/count)
count += 1
return my_list
my_list = is_prime(18)
def prime(x):
my_list2 = []
for number in my_list:
if number <= 2:
my_list2.append(number)
else:
count = 2
while count < number:
if number % count == 0:
break
else:
my_list2.append(number)
count += 1
return my_list2
print prime(18)
Just started out with Python. I have a very simple question.
This prints: [9, 3, 2].
Can someone please tell me why the loop inside my else stops at count = 2? In other words, the loop inside my loop doesn't seem to loop. If I can get my loop to work, hopefully this should print [2, 3]. Any insight is appreciated!
Assuming that my_list2 (not a very nice name for a list) is supposed to contain only the primes from my_list, you need to change your logic a little bit. At the moment, 9 is being added to the list because 9 % 2 != 0. Then 9 % 3 is tested and the loop breaks but 9 has already been added to the list.
You need to ensure that each number has no factors before adding it to the list.
There are much neater ways to do this but they involve things that you may potentially find confusing if you're new to python. This way is pretty close to your original attempt. Note that I've changed your variable names! I have also made use of the x that you are passing to get_prime_factors (in your question you were passing it to the function but not using it). Instead of using the global my_list I have called the function get_factors from within get_prime_factors. Alternatively you could pass in a list - I have shown the changes this would require in comments.
def get_factors(x):
count = 1
my_list = []
while count > 0 and count < x:
if x % count == 0:
my_list.append(x/count)
count += 1
return my_list
# Passing in the number # Passing in a list instead
def get_prime_factors(x): # get_prime_factors(factors):
prime_factors = []
for number in get_factors(x): # for number in factors:
if number <= 2:
prime_factors.append(number)
else:
count = 2
prime = True
while count < number:
if number % count == 0:
prime = False
count += 1
if prime:
prime_factors.append(number)
return prime_factors
print get_prime_factors(18)
output:
[3, 2]
Just to give you a taste of some of the more advanced ways you could go about doing this, get_prime_factors could be reduced to something like this:
def get_prime_factors(x):
prime_factors = []
for n in get_factors(x):
if n <= 2 or all(n % count != 0 for count in xrange(2, n)):
prime_factors.append(n)
return prime_factors
all is a built-in function which would be very useful here. It returns true if everything it iterates through is true. xrange (range on python 3) allows you to iterate through a list of values without manually specifying a counter. You could go further than this too:
def get_prime_factors(x):
return [n for n in get_factors(x) if n <= 2 or all(n % c != 0 for c in xrange(2, n))]