Add number per count? - python

I want to make a program on Python that will add 5 per count until count is 20, so the total would be 100. So basically I want to show the result of 5 * 20 using this way.
num = 5
count = 0
total = 0
I tried this code but it returns as zero. Why?
while(count == 20):
total = num * count
if(total == num * count):
count = count + 1
print total
Please fix any mistake I made. I'm new to Python...

You probably meant while count <= 20:
The condition specified for a while loop is what needs to be true for it to keep running - not for when it ends.
Also note that you don't need parentheses around the while and if conditions.
Your code also has some odd redundancies, though.
For instance:
total = num * count
if total == num * count:
count = count + 1
The if statement will always be true, given that you're setting total to the same thing you check it against, in the previous line. In other words, you could have just written...
total = num * count
if True:
count = count + 1
or even just...
total = num * count
count = count + 1
Furthermore...
You set total equal to num * count on each iteration, but if your goal is just to print out num * 20, you don't have to count up to 20 - you can just start out at 20.
num = 5
count = 20
print num * count
Also note...
that this line can be more concisely stated:
count = count + 1
can also just be written as...
count += 1
Finally...
If what you really wanted was a list of numbers in increments of 5 up to 100, you could do this:
>>> range(0, 101, 5)
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]
or this:
>>> [n*5 for n in range(21)]
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]

Related

How do I save incremented Numbers and calculate them?

I want to write myself a program where a variable is going to increment everytime in the while-loop and want at the end, that all values will be stored in a list. At the end the values of the list should be summed with sum().
My problem is that when I execute my program it just let me show the last number of all. I want to have like l = [5,10,15,...,175] and not just l = [175] (I hope its clear what I mean)
def calc_cost():
x = 0
k = 34
j = 0
while x <= k:
x = x + 1
j = j + 5
l = []
l.append(j)
print(sum(l))
print(calc_cost())
def calc_cost():
x = 0
k = 34
j = 0
l = []
while x <= k:
x = x + 1
j = j + 5
l.append(j)
print(l)
return sum(l)
print(calc_cost())
I made the edit I suggested. I also returned the sum so it could be printed by the line: print(calc_cost())
Here is the output:
[5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, 175]
3150
Here's a similar approach using the range function:
def calc_cost():
k = 34
l = list( range( 5, (k+2) * 5, 5 ) )
print(l)
return sum(l)
print(calc_cost())

inventory update in a pythonic way

I'm working on a time-series problem, and I have a list of events such that each data point represent several objects being pulled from an inventory.
Each time the value reaches below some threshold, I want to add a constant number to the inventory.
For example, I want:
(threshold = 55, constant = 20)
70 60 50 45 30 0 -5 -75
to become:
70 60 70 65 70 60 75 25
Is there a "pythonic" way (pandas, numpy, etc...) to do it with no loops?
Edit: the addition of constant can occur multiple times, and only effect the future (i.e indexes that are greater than the observed index). This is the code I'm using right now, and my goal is to lose the for loop:
threshold = 55
constant = 20
a = np.array([70, 60, 50, 45, 30, 0, -5, -75])
b = a.copy()
for i in range(len(b)):
if b[i] <= threshold:
temp_add_array = np.zeros(b.shape)
indexes_to_add = np.array(range(len(b))) >= i
temp_add_array[indexes_to_add] += constant
b += temp_add_array.astype(int)
print(b)
print('*************')
print('[70 60 70 65 70 60 75 25]')
Since you're allowing for numpy:
>>> import numpy as np
# threshold and constant
>>> t, c = 55, 20
>>> data = np.asarray([70, 60, 50, 45, 30, 0, -5, -75])
# if you allow for data == threshold
>>> np.where(data >= t, data, data + c*((t-1-data) // c + 1))
array([70, 60, 70, 65, 70, 60, 55, 65])
# if you enforce data > threshold
>>> np.where(data > t, data, data + c*((t-data) // c + 1))
array([70, 60, 70, 65, 70, 60, 75, 65])
But there is really no need for an external dependency for a task like that
# threshold and constant
>>> t, c = 55, 20
>>> data = [70, 60, 50, 45, 30, 0, -5, -75]
# if you allow for data == threshold
>>> [x if x >= t else x + c*((t-1-x)//c + 1) for x in data]
[70, 60, 70, 65, 70, 60, 55, 65]
# if you enforce data > threshold
>>> [x if x > t else x + c*((t-x)//c + 1) for x in data]
[70, 60, 70, 65, 70, 60, 75, 65]
Edit of OP
I doubt there's a (readable) solution for your problem without using a loop; best thing I could come up with:
>>> import numpy as np
>>> a = np.asarray([70, 60, 50, 45, 30, 0, -5, -75])
# I don't think you *can* get rid of the loop since there are forward dependencies in the the data
>>> def stock_inventory(data: np.ndarray, threshold: int, constant: int) -> np.ndarray:
... res = data.copy()
... for i, e in enumerate(res):
... if e <= threshold:
... res[i:] += constant
... return res
...
>>> stock_inventory(a, threshold=55, constant=20)
array([70, 60, 70, 65, 70, 60, 75, 25])
Assuming a numpy ndarray...
original array is named a
subtract the threshold value from a - name the result b
make a boolean array of b < 0 - name this array c
integer/floor divide b by -1 * constant - name this d (it could be named b as it is no longer needed)
add one to d - name this e
use c as a boolean index to add e to a for those values that were less than the threshold. a[c] += e[c]

find frequency of numbers in intervals

What would be the most efficient way to find the frequency/count of elements in non-overlapping intervals? For example:
limits = [0, 25, 40, 60]
data = [15, 5, 2, 56, 45, 23, 6, 59, 33, 18]
For the above lists, I want to find the number of elements in data that are within two adjacent limits. So for the above, the count would be something like:
0-25: 6;
25-40: 1;
40-60: 3;
All I can think of is O(n^2) in time. Is there a better way to do it?
Doesn't need Counter to count as number of bins is known, swaps dict to array accesses for binning..
from bisect import bisect_right
def bin_it(limits, data):
"Bin data according to (ascending) limits."
bins = [0] * (len(limits) + 1) # adds under/over range bins too
for d in data:
bins[bisect_right(limits, d)] += 1
return bins
if __name__ == "__main__":
limits = [0, 25, 40, 60]
data = [15, 5, 2, 56, 45, 23, 6, 59, 33, 18]
bins = bin_it(limits, data)
print(f" < {limits[0]:2} :", bins[0])
for lo, hi, count in zip(limits, limits[1:], bins[1:]):
print(f">= {lo:2} .. < {hi:2} :", count)
print(f">= {limits[-1]:2} ... :", bins[-1])
"""
SAMPLE OUTPUT:
< 0 : 0
>= 0 .. < 25 : 6
>= 25 .. < 40 : 1
>= 40 .. < 60 : 3
>= 60 ... : 0
"""
I recommend you this approach which implements what you want in order of O(nlogn)
limits = [0, 25, 40, 60] # m
data = [15, 5, 2, 56, 45, 23, 6, 59, 33, 18] # n
data += limits # O(n+m)
data.sort() # O((n+m)log(n+m)) = O(nlogn)
result=dict() # O(1)
cnt = 0 # O(1)
aux ='' # O(1)
i = 0 # O(1)
for el in data: # O(n+m)
if el == limits[i]:
i+=1
if cnt > 0:
aux+='-'+str(el)
result[aux] = cnt # average = O(1)
cnt = 0
aux = str(el)
else:
aux = str(el)
else:
cnt+=1
print(result)
# {'0-25': 6, '25-40': 1, '40-60': 3}
I showed the time complexity of each important line to calculate the total time complexity of the code. the total time complexity of the code is equal to O((n+m)log(n+m)) which can be shown as O(nlogn).
Improvement
you can improve it if you have some assumptions about the inputs. if you have info about the range of limits and data, then you can change the sorting algorithm to counting sort. the time complexity of counting sort is considered as O(n) and the total time complexity of code would be O(n)
Here is a simple O(NlogN) approach. Sort your data, then use a two pointer approach to place each element in the correct interval.
limits = [0, 25, 40, 60]
data = [15, 5, 2, 56, 45, 23, 6, 59, 33, 18]
data.sort()
n,m = len(data), len(limits)
count = [0]*(m-1)
# count[i] represents count between limits[i] and limits[i+1]
low = 0 # lower index of interval we are currently checking
ptr = 0
while ptr < n:
i = data[ptr]
if i >= limits[low] and i <= limits[low+1]:
count[low] += 1
ptr += 1
elif i>=limits[low]:
if low == len(limits)-1:
break
low += 1
print(count)
limits = [0, 25, 40, 60, 80]
data = [15, 5, 2, 56, 45, 23, 6, 59, 33, 18, 25, 45, 85]
dict_data = {}
i = 0
count = 1
while i < len(limits)-1:
for j in data:
if j in range(limits[i], limits[i+1]):
if '{}-{}'.format(limits[i],limits[i+1]) in dict_data:
dict_data['{}-{}'.format(limits[i],limits[i+1])] +=count
else:
dict_data['{}-{}'.format(limits[i],limits[i+1])] = count
i+=1
print(dict_data)
You could use Counter (from collections) to manage the tallying and bisect to categorize:
from collections import Counter
from bisect import bisect_left
limits = [0, 25, 40, 60, 80]
data = [15, 5, 2, 56, 45, 23, 6, 59, 33, 18]
r = Counter(limits[bisect_left(limits,d)-1] for d in data)
print(r)
Counter({0: 6, 40: 3, 25: 1})
This has a time complexity of O(NLogM) where M is the number of limit breaks and N is the number of data items

Python: How to efficiently count the number of "1"s in the binary representation of 1 to n numbers?

E.g. For the input 5, the output should be 7.
(bin(1) = 1, bin(2) = 10 ... bin(5) = 101) --> 1 + 1 + 2 + 1 + 2 = 7
Here's what I've tried, but it isn't a very efficient algorithm, considering that I iterate the loop once for each integer. My code (Python 3):
i = int(input())
a = 0
for b in range(i+1):
a = a + bin(b).count("1")
print(a)
Thank you!
Here's a solution based on the recurrence relation from OEIS:
def onecount(n):
if n == 0:
return 0
if n % 2 == 0:
m = n/2
return onecount(m) + onecount(m-1) + m
m = (n-1)/2
return 2*onecount(m)+m+1
>>> [onecount(i) for i in range(30)]
[0, 1, 2, 4, 5, 7, 9, 12, 13, 15, 17, 20, 22, 25, 28, 32, 33, 35, 37, 40, 42, 45, 48, 52, 54, 57, 60, 64, 67, 71]
gmpy2, due to Alex Martella et al, seems to perform better, at least on my Win10 machine.
from time import time
import gmpy2
def onecount(n):
if n == 0:
return 0
if n % 2 == 0:
m = n/2
return onecount(m) + onecount(m-1) + m
m = (n-1)/2
return 2*onecount(m)+m+1
N = 10000
initial = time()
for _ in range(N):
for i in range(30):
onecount(i)
print (time()-initial)
initial = time()
for _ in range(N):
total = 0
for i in range(30):
total+=gmpy2.popcount(i)
print (time()-initial)
Here's the output:
1.7816979885101318
0.07404899597167969
If you want a list, and you're using >Py3.2:
>>> from itertools import accumulate
>>> result = list(accumulate([gmpy2.popcount(_) for _ in range(30)]))
>>> result
[0, 1, 2, 4, 5, 7, 9, 12, 13, 15, 17, 20, 22, 25, 28, 32, 33, 35, 37, 40, 42, 45, 48, 52, 54, 57, 60, 64, 67, 71]

Find number of prime numbers between 2 and n

I am trying to find the number of prime numbers between 2 and n, where n is provided by the user. I can't seem to make it work. here's my code:
>>> def numOfPrime(n):
count = 0
for i in range(2,n):
p = True
for j in range(2,i):
if i % j ==0:
p = False
if p == True:
count += 1
return count
>>> numOfPrime(100)
0
The indentation of your if block is incorrect. It should be in the loop.
def numOfPrime(n):
count = 0
for i in range(2,n):
p = True
for j in range(2,i):
if i % j ==0:
p = False
if p == True:
count += 1
return count
Now numOfPrime(100) returns 25, which correctly accounts for 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, and 97.

Categories