I am new at coding and i am trying to do a collatz conjecture.
I think i already made it by i cant code a way to count how much "steps" it takes to the 1.
This is the code i already did.
n = int(input("Enter a number!"))
def lothar(n):
print(n)
if n == 1:
return i
if n % 2 == 0:
n = n / 2
else:
n = ((n*3) + 1)
return lothar(n)
print(lothar(n))
I want to count using a while structure.
For example: in number 4 , it takes 3 steps.
4
2
1.
There's a few ways to count the steps, but I've gone with removing the recursion and using a loop instead:
n = int(input("Enter a number: "))
def lothar(n):
steps = [n]
while n > 1:
if n % 2 == 0:
n = n // 2
else:
n = ((n*3) + 1)
steps.append(n)
return steps
sequence = lothar(n)
print(sequence)
print(str(len(sequence)-1) + " step(s)")
That will return the sequence, which then means we can display the sequence and also output the amount of steps (i.e. the length of the sequence minus one).
For example:
Enter a number: 9
[9, 28, 14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
19 step(s)
Put the while loop into the function, and give a count variable for counting.
n = int(input("Enter a number!"))
count = 1
def lothar(n,count):
while n != 1:
if n % 2 == 0:
count += 1
n = n / 2
else:
count += 1
n = ((n*3) + 1)
return count
print(lothar(n,count))
Because the result you want is to include 4, count will be added one more time, but if you want to count the number of loops, you should set count to 0 for calculation.
Related
I wonder if there is any function in python like that.
Example 01:
For example, if I specify the range from (1,12) integer. Then:
if current value is 12 and I add 1, it return 1 (go back to minimum)
if current value is 11 and I add 3, it return 2
Example 02:
Another example is if I set range from (5, 9). Then:
If current value is 8 and I add 2, it return 5
If current value is 8 and I add 7, it return 5
I know I can write a self-defined function for that, I am just curious to know if python has that similar function built in
The self-defined function:
def wrap_range(val, nmin, nmax, add_val):
nrange = nmax - nmin + 1
remain = add_val % nrange
val = val + remain
if val <= nmax:
return val
else:
val = val - nmax + nmin - 1
return val
Itertools has the cycle and islice functions that you can use to get what you want -
from itertools import cycle, islice
def repeated_offset(nmin, nmax, start, n):
rng = range(nmin, nmax + 1)
start_idx = list(rng).index(start)
value, *_ = islice(cycle(rng), start_idx + n, start_idx + n + 1)
return value
repeated_offset(1, 12, 12, 1)
# 1
repeated_offset(1, 12, 11, 3)
# 2
repeated_offset(5, 9, 8, 2)
# 5
repeated_offset(5, 9, 8, 7)
# 5
What about looping, subtracting while the total value is bigger than the lower boundary, while subtracting range wide.
def loopit(val, the_min, the_max, addition):
total = val + addition
diff = the_max - the_min + 1
if not total > the_min:
raise ValueError("The total value must be larger then lowest boundary of the range")
while the_max < total:
total -= diff
return total
if __name__ == '__main__':
print(loopit(12, 1, 12, 1))
print(loopit(11, 1, 12, 3))
print(loopit(8, 5, 9, 2))
print(loopit(8, 5, 9, 7))
output:
1
2
5
5
This question already has an answer here:
Dividing multiple numbers in a list
(1 answer)
Closed 1 year ago.
So what I'm trying to do is find the total number of 1 dollar, 2 dollar, 5 dollar and 10 dollar bills needed to equal a number v: int and i'm kinda stuck on how to do it...
Here is my code so far..
def coinChange(v: int):
while x == 1 and x == 2 and x == 5 and x == 10:
if x + x + x + x == v:
return x
Like its definitely wrong, so what am I doing wrong here and what should I do to fix it? Btw, the output should be a list, so like... if coinChange(38) is the input, the output should be [10,10,10,5,2,1] What is the right code to make sure I get the right output?
You can use integer division (//) and modulus (%) operations to determine the number of each denomination required.
def coinChange(v: int):
tens = v // 10
remainder = v % 10
fives = remainder // 5
remainder = remainder % 5
twos = remainder // 2
ones = remainder % 2
coins = [10 for n in range(tens)]
coins += [5 for n in range(fives)]
coins += [2 for n in range(twos)]
coins += [1 for n in range(ones)]
return coins
The code can be reduced using a loop:
def coinChange(v: int):
coins = [10, 5, 2, 1]
change = []
for c in coins:
change += [c for n in range(v // c)]
v = v % c
return change
The result for both implementations will be the same:
coinChange(38) # [10, 10, 10, 5, 2, 1]
Try using this code instead.
def change(amount):
money = ()
for coin in [10,5,2,1]:
num = amount/coin
money += (coin,) * num
amount -= coin * num
return money
Easiest logic and you can understand it make sure to start with greater like check 10 first then 5 and then 2 and then 1
def coinChange(x):
coins = []
while x != 0:
if x >= 10:
x = x - 10
coins.append(10)
elif x >= 5:
x = x - 5
coins.append(5)
elif x >= 2:
x = x - 2
coins.append(2)
elif x >= 1:
x = x - 1
coins.append(1)
print(coins)
coinChange(38)
I've been making a program that finds two numbers in a random list and prints them if their sum is 8.
Honestly, I've been sitting here for half an hour and idk what's going on. I think I'm pretty close, but in rare cases it doesn't find an exitsting combination(list = [1,4,4,9] -> No combination). Also in rare cases I will get an error saying
RecursionError: maximum recursion depth exceeded in comparison
Here's my code:
import random
list = []
for i in range(1,5,1):
newNum = random.randint(1,10)
list.append(newNum)
list.sort()
sum = 8
print('\nRandomly generated list:')
print(list)
firstNum = list[0]
lastNum = list[-1]
newList = []
def isSum(a,b):
if a + b == sum:
if list.index(a) == list.index(b):
print('\nThere isnt a combination.')
else:
newList.append(a)
newList.append(b)
print('\nCombination:')
print(newList)
elif a + b < sum:
temp = list.index(a)
temp += 1
if temp > list.index(lastNum):
print('\nThere isnt a combination.')
else:
a = list[temp]
isSum(a,b)
else:
temp = list.index(b)
temp -= 1
if temp < list.index(firstNum):
print('\nThere isnt a combination.')
else:
b = list[temp]
isSum(a,b)
isSum(firstNum,lastNum)
I'm just a beginner, don't get angry if I made a stupid mistake :3
You can use itertools module for generating all combinations of your list, then filter that by calculating the sum of each combination, for example this:
import itertools
a = [1, 4, 4, 9] # any list of nums
groups = 2
result = 8
combinations = [combination for combination in itertools.combinations(a, groups)]
output = [combination for combination in combinations if sum(combination) == result]
print(output)
>>> [(4, 4)]
Recursion really isn't ideal in Python, and your code could certainly be simplified.
This should return all the pairs.
import itertools as itt
import random
from typing import List, Tuple
def is_comb_sum(nums: List[int], comb_size: int, target_sum: int) -> List[Tuple[int, ...]]:
combs = []
for curr_pair in itt.combinations(nums, comb_size):
curr_sum = sum(curr_pair)
if curr_sum == target_sum:
combs.append(curr_pair)
return combs
nums_list = [random.randint(0, 10) for _ in range(5)]
print(nums_list)
res = is_comb_sum(nums_list, 2, 8)
print(res)
If you only want to print each combination once, you can use a set to identify the distinct numbers that are present. Then, for each of these number, you determine which complementing value is need to reach your target (8) and if it is also in the set then the pair exists. The only exception to this is when the number is exactly half of the target (i.e. 4) in which case you have to make sure there are at least two instances of that number in the list:
target = 8
count = 4
numbers = [random.randint(1,10) for _ in range(count)]
print(numbers)
numberSet = set(numbers)
for number in numberSet:
other = target-number
if other not in numberSet: continue
if other > number: continue # avoid duplicates such as 2+6=8 and 6+2=8
if other == number and numbers.count(number) < 2: continue
print(number,"+",other,"=",target)
Output:
[7, 2, 6, 1]
6 + 2 = 8
7 + 1 = 8
If you want to print all the combinations, you can use the Counter object from the collection modules and either print the number of occurrences or repeat the printed lines:
target = 12
count = 8
numbers = [random.randint(1,10) for _ in range(count)]
print(numbers)
from collections import Counter
numberCounts = Counter(numbers)
for number in numberCounts:
other = target-number
if other > number: continue
pairCount = numberCounts[number] * numberCounts[other]
if number == other:
pairCount = (pairCount - numberCounts[number]) // 2
if pairCount > 0:
print(number,"+",other,"=",target,"occurred",pairCount,"time(s)")
Output (target of 12 in list of 8):
[7, 6, 5, 5, 6, 6, 3, 4]
7 + 5 = 12 occurred 2 time(s)
6 + 6 = 12 occurred 3 time(s)
So I have this code :
from random import *
from math import *
n=int(input("n="))
sommes = [0]*12
for i in range(1,n+1):
r=randint(1,6)+randint(1,6)
if r==1:
sommes[0] += 1
if r==2:
sommes[1] += 1
if r==3:
sommes[2] += 1
if r==4:
sommes[3] += 1
if r==5:
sommes[4] += 1
if r==6:
sommes[5] += 1
if r==7:
sommes[6] += 1
if r==8:
sommes[7] += 1
if r==9:
sommes[8] += 1
if r==10:
sommes[9] += 1
if r==11:
sommes[10] += 1
if r==12:
sommes[11] += 1
print(sommes)
And I want to know if I can reduce/optimise that part :
for i in range(1,n+1):
r=randint(1,6)+randint(1,6)
if r==1:
sommes[0] += 1
if r==2:
sommes[1] += 1
if r==3:
sommes[2] += 1
if r==4:
sommes[3] += 1
if r==5:
sommes[4] += 1
if r==6:
sommes[5] += 1
if r==7:
sommes[6] += 1
if r==8:
sommes[7] += 1
if r==9:
sommes[8] += 1
if r==10:
sommes[9] += 1
if r==11:
sommes[10] += 1
if r==12:
sommes[11] += 1
And how can I make sure to give the result as a percentage for each number in the list (1 to 12) like
that [2, 23, 4, 48, 21] to that [2%, 12%, 4%, 43%, 23%]
You already have an integer, r. You can just use r-1 as the index to sommes
from random import randint
n=int(input("n="))
sommes = [0]*12
for i in range(1,n+1):
r=randint(1,6)+randint(1,6)
sommes[r-1] += 1
For the percentages part you can just divide everything by n and multiply by 100:
y = [int(x/n*100) for x in sommes]
(although if you use integers as in your example, it won't add up to 100).
or if you want a list of strings with percentages you can use this format. This does have the advantage that you can control how many decimal places the strings have. .0f is 0, but you could change the 0 for the number of decimal places you want.
y = [f"{x/n*100:.0f}%" for x in sommes]
I've also optimised the inputs as it's not efficient to use from random import * if you're only using randint
Notice how you're always using an index of r-1 to access and update your sommes array.
With that in mind, your code could be simplified to:
for i in range(1,n+1):
r=randint(1,6)+randint(1,6)
sommes[r-1] += 1
As for calculating percentages, you could print the result as:
print("%.0f%%" % (100 * sommes[i] / n))
This will limit your number to not showing decimals (%.0f) and show your number of occurrences for each number divided by the total number of dices.
Leveraging Counter from the standard library:
from random import *
from math import *
from collections import Counter
#n=int(input("n="))
n=10 # for example
r = range(n)
rands = (randint(1,6)+randint(1,6) for _ in r)
sommes = Counter(rands)
print(sommes)
perc = [int(sommes[i]/n*100) for i in r]
print(perc)
produces
Counter({3: 2, 6: 2, 12: 2, 7: 1, 11: 1, 9: 1, 8: 1})
[0, 0, 0, 20, 0, 0, 20, 10, 10, 10]
I'm trying to find the avg of list but only when n >= 10 (two digit numbers, my original list is limited to 100).
Here's what I have right now:
# Calculate average of all two-digit numbers (10-99)
grade_list = [10, 11, 12, 13, 14, 15]
def calcAvg(grade_list):
while n > 10:
total = sum(grade_list)
n = total % len(grade_list)
print_list = n
return print_list
I get that I have to find the total sum of the list when n > 10 and then dividing by the length (only > 10, my original list has single digit elements, so I'd like to avoid them).
But when I run it, I get an error saying: local variable 'n' referenced before assignment
Any help on how to structure this function to achieve the end results (sum/total of only 2-digit elements = avg)
Thanks!
I'd either collect the good grades and use sum/len, or use the mean function:
>>> grade_list = [1, 2, 10, 11, 12, 13, 14, 15]
>>> good = [g for g in grade_list if g > 10]
>>> sum(good) / len(good)
13.0
>>> import statistics
>>> statistics.mean(g for g in grade_list if g > 10)
13.0
def calcAvg(grade_list):
my_list = []
total, count = 0,0
for n in grade_list:
if 10 <= n <= 99:
total += n
if not total:
return None
return total/count
Here is a clean way of doing it:
def calc_avg(lst):
filtered_lst = filter(lambda x: 10 < x < 100, lst)
return sum(filtered_lst) / len(filtered_lst)
So you should use a for loop instead of a while loop. Instead of having two for loops and making a new list, you could just account for the sum inside the first for loop. I demonstrate this below.
def calcAvg(grade_list):
sum = 0;
count = 0;
for n in grade_list:
if 10 <= n <= 99:
sum = sum + n
count = count + 1
return sum/count
I think you should manually go over the code step by step and try to understand what is wrong. Meanwhile this may give you some hints
# Calculate average of all two-digit numbers (10-99)
def calcAvg(alist):
count=total=0
for i in alist:
if 9 < i < 100:
total += i
count += 1
return total/count
Since Python 3.4 there is a statistics module.
So you just need to filter out numbers in range <10,100), for example with a list comprehension, and then pass this filtered list to the mean function. Simple as that.
from statistics import mean
numbers = [1, 20, 30, 50]
mean([n for n in numbers if n >= 10 and n < 100])
>>> 33.333333333333336
You could do this fairly simply with a list comprehension
>>> grades = [1, 2, 10, 11, 12, 13, 14, 15, 120, 122, 320]
>>> lst = [v for v in grades if 10 <= v < 100]
>>> sum(lst)/len(lst)
12