I'm new to programming and was asked to sum odd numbers from 1 to (2*n)-1 using a while loop.
This is my attempt:
def sum_odd_n(n):
while n<2*n:
sum = 0
if n%2==1:
sum = sum+n
return (sum)
May i know my mistake? Any help will be appreciated
The condition while n<2*n: is always true while n >= 0, you'll have an infinite loop. Try the following
def sum_odd(n):
value = 1
total = 0
while value < (2*n) - 1:
if value % 2 == 1:
total += value
value += 1
return total
>>> sum_odd(25)
576
For completeness the more pythonic way to handle this would be using sum with a generator expression
def sum_odd(n):
return sum(i for i in range(1, 2*n -1) if i%2 == 1)
The first hint would be to take a look at your condition in while loop:
while n < 2*n
Notice that this will always be true, because if n>0, then 2*n is always greater. If you need more help, write a comment ;)
UPDATE: I will just tell you what is wrong so if you want to try it out first on your own, stop reading. So basically you need another variable, let's say i that will loop through integers. Then you can do something like this:
def sum_odd_n(n):
i = n
sum = 0
while i < 2*n:
if i % 2 == 1:
sum += i
i += 1
print sum # for python3: print(sum)
>>> def sum_odd_n(n):
... return sum([2 ** i for i in range(0,n,1) ])
...
>>> sum_odd_n(2)
3
>>> sum_odd_n(5)
31
>>>
I'll try to point out the mistakes you have done, and try to offer corrections.
def sum_odd_n(n):
while n<2*n: # n will always be less than ('<') 2*n. For eg, if n=5, 5<10.
sum = 0 # you are resetting the sum at every iteration. We need to take this outside.
if n%2==1:
sum = sum+n
return (sum)
Here's what I think should work.
def sum_odd_n(n):
sum = 0 # sum is initialized here, so that it doesn't reset inside the loop
iterator = 0
while iterator<2*n
if iterator%2==1:
sum = sum+iterator # or sum += iterator
iterator = iterator + 1 # otherwise this will be an infinite loop, as iterator will always be 0.
return sum
Hope this works for you. :-)
This worked for me:
def sum_odd(n: int):
total = 0
for x in range(2*n):
if x%2==1:
total += x
return total
Related
i am an absolute Beginner in Python and im trying to, find happy numbers from a given List. but it doesn't give anything back, i searched for a solution but i couldnt find one. My code is this :
a = [1,4,7,82]
def is_happy(a):
for i in range (len(a)):
sum = a[i]
for digit in str(a[i]):
sum = 0
while sum != 1 and sum !=4:
sum = sum + int(digit) ** 2
if sum ==1:
b.append(a[i])
return b
print(is_happy(a))
May you can help me. Thank you!
Converting the integers to strings in order to calculate the sum of squares is not a great idea - better to combine division and modulus. Write a discrete function to do that.
Then write a function that handles one value at a time. Call that multiple times - once for each item in your list.
Here's an approach you could use:
def ss(n):
r = 0
while n > 0:
d = n % 10
r += d * d
n //= 10
return r
def is_happy(n):
if n > 0:
while True:
if (n := ss(n)) == 1:
return True
if n == 4:
break
return False
a = [1, 4, 7, 82]
for n in a:
print(n, is_happy(n))
Output:
1 True
4 False
7 True
82 True
the indents of Python made me suffer..
my solution now looks like:
a = [8,2,7,82]
b = []
def is_happy(a):
for i in range (len(a)):
sum = a[i]
while sum!=1 and sum !=4:
tempsum = 0
for digit in str(sum):
tempsum += int(digit) ** 2
sum = tempsum
if sum == 1:
b.append(a[i])
return b
print(is_happy(a))
and works fine. Thanks for your help and suggestions
Eminos,
I will help with some suggestions.
In Python, white space is very important, and it takes some time for any newbie to get used to.
In for i in range (len(a)):, there is an extra space between "range" and "(". It could still run, but is not the preferred style, since it is defined as a range() function.
Code blocks need consistent spacing (left indent). Each level should be 2 or 4 spaces, with 4 spaces recommended by PEP8 (not tabs). The below examples have too many spaces in left indent.
sum = 0
sum = sum + int(digit) ** 2
b.append(a[i])
To calculate the squre of a number, it is not necessary to change data type from integer to string.
squared = a[i]**2
To keep track of your squared numbers list, try:
tally = 0
for i in range(len(a)):
squared = a[i]**2 # squares each number in list
tally += squared # keeps a running sum of squared numbers
Generally, I think a function like is_happy should return a true/false statement(s). So a sample returned list can be ["True", "False", "True", "True"] for your input example [1, 4, 7, 82].
More work to do, but hope that will get you started. :-)
import math
class Solution:
def countSquares(self, N):
list = []
count = 0
for i in range(1,(int)(math.sqrt(N))):
square = i ** 2
list.append(square)
count = count + 1
return count
I am trying to count the number of perfect squares that are less than a given 'N'.
For example, if N = 9, the output is 2. Because only 1 & 4 are the perfect squares present.
list(map(lambda x:x*x, range(1,1+int(math.sqrt(n-1)))))
I think this should do it.
math.ceil(math.sqrt(n)) - 1
math.sqrt will output the square root of the current number.
math.ceil converts that number into the next whole number.
- 1 gives you the previous whole number, which is also the (inclusive) count of whole numbers which can be squared to a number less than n.
If you need to get the list of the square roots instead of the count the modifications are simple.
list(range(1, math.ceil(math.sqrt(n))))
In this case - 1 doesn't need to be performed so range ends with the correct number.
count = 0
for i in range(1, X):
#...
count = count + 1
ends with count == X - 1. Therefore, you don't really need a loop. You also never actually use the list, so storing it will slow down the program further.
sq = math.sqrt(N)
if math.floor(sq) < sq <= math.ceil(sq):
return int(sq)
return int(sq) - 1
Try this:
import math
class Solution:
def countSquares(self, N):
n = math.floor(math.sqrt(N))
if n * n == N:
return n - 1
else:
return n
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())))
[![enter image description here][1]][1]
First function returns the recursive digit sum of that number. The second function return dictionary where key is reg_dig_sum and value is count of that number occurring. when I tested it it failed giving me this
elf.assertEqual(sum_dict[0], 1)
AssertionError: 0 != 1
How can I solve this?
def reg_dig_sum(n):
x = sum(int(digit) for digit in str(n))
if x < 10:
return x
else:
return reg_dig_sum(x)
def distr_of_rec_digit_sums(low=0, high=1500):
distr = {}
for x in range(low, high):
if reg_dig_sum(x) not in distr:
distr[reg_dig_sum(x)] = 0
else:
distr[reg_dig_sum(x)] += 1
return distr
The problem I can think is your count for each reg_dig_sum will be one less than what it should be. That's the reason assertion condition is failing.
You can fix this logical error by initializing distr to either 1 or by removing else condition.
I would also suggest to use other alternatives like defaultdict to take care of initialization for you.
def distr_of_rec_digit_sums(low=0, high=1500):
distr = {}
for x in range(low, high):
if reg_dig_sum(x) not in distr:
distr[reg_dig_sum(x)] = 1 # this should be initialized to 1 for first occurance.
else:
distr[reg_dig_sum(x)] += 1
return distr
Using defaultdict
from collections import defaultdict
def distr_of_rec_digit_sums(low=0, high=1500):
distr = defaultdict(int)
for x in range(low, high):
distr[reg_dig_sum(x)] += 1
return distr
See previous comments and answers regarding changing 0 to 1
Also try to use much simpler code for reg_dig_sum with the same result:
def reg_dig_sum(n):
return (n - 1) % 9 + 1
I've used a simple function to do this for a long time:
def sum_digits(num):
if num <= 9:
return num
num = int(num / 10) + num - int(num / 10) * 10
''' takes the last digit of num off, and adds it to num. '''
return sum_digits(num)
There are a lot of things you can find with this function. Try this on the power series, and you'll see what I mean. Really any mathematical function you could use on a number line will return interesting patterns; this function helps you see part of that.
New to coding and am trying to solve this coding problem to learn.
Prompt:
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all the multiples of 3 or 5 below 1000.
three = []
five = []
def threeList():
n = 1
while (n*3<1000):
result = n*3
three.append(result)
n += 1
return three
def fiveList():
n = 1
while (n*5<1000):
result = n*5
five.append(result)
n += 1
return five
threeList()
fiveList()
print(three,five)
This results in printing [3] [5] to the console.
Your return is part of the loop which means that at the end of iteration, instead of doing another iteration you just return from the function. Move it out of a loop, i.e.:
def threeList():
n = 1
while (n*3<1000):
result = n*3
three.append(result)
n += 1
return three
Also this return makes little sense, because you are returning global variables. No point to return something that is already available (I suggest you read about variable scope), so it's safe to get rid of these returns completely:
def threeList():
n = 1
while (n*3<1000):
result = n*3
three.append(result)
n += 1
In fact, as both your functions differ very little, you should refactor your code and have just one function accepting the multiplier (as this is the only difference) and return populated list. This time we go with local variable to create the result list, so this time you need to return it otherwise result list will not be available outside the function:
def my_func(multiplier):
result = []
n = 1
while (n*multiplier < 1000):
result.append(n*multiplier)
n += 1
return result
and then replace
threeList()
fiveList()
with
three = my_func(3)
five = my_func(5)
In fact, you could merge this with print() as there's no other use for three and five, so your final code would then look like this:
def my_func(multiplier):
result = []
n = 1
while (n*multiplier < 1000):
result.append(n*multiplier)
n += 1
return result
print(my_func(3), my_func(5))
In addition to Marcin's fantastic answer, note that you can also do the math for which elements to use ahead of time and avoid the while loop entirely. range is your friend here.
multiples_of_five = range(5, 1001, step=5)
multiples_of_three = range(3, 1001, 3)
Since range's stop is exclusive, but we want all the multiples of three and five up to 1000 inclusive, we have to stop at 1001 instead. This simplifies the my_func that Marcin lays out above.
def list_multiples(n):
result = []
for i in range(n, 1001, n):
result.append(i)
return result
Though if we examine this more closely, you'll see we're basically just casting to list and returning. Let's do that directly.
def list_multiples(n):
return list(range(n, 1001, n))
From there we can find the multiples of five and multiples of three
fives = list_multiples(5)
threes = list_multiples(3)
Cast to set to remove duplicates (15 is a multiple of both 5 and 3, but shouldn't be summed twice)
all_nums = set(fives + threes)
And sum the result
result = sum(all_nums)
To solve your problem in Pythonic way, use sum() with a generator expression like:
Code:
sum(i for i in range(1000) if i % 5 == 0 or i % 3 == 0)
Test Code:
max_num = 1000
print(sum(i for i in range(max_num) if i % 5 == 0 or i % 3 == 0))
Results:
233168