My concern was what is a good way to generate a list of 10 - 15 numbers that the sum of them always divisible by n.
The output should be
-8378302799
Here what I got so far, but it not a working script yet.
import random
import numpy as np
def get_num(x, y, n):
return [random.choice(range(x, y, n)) if x % n != 0 else random.choice(range(x - (x % n) + n, y, n)) for x in x]
def get_list():
numb = get_num(0, 9, 2)
return ''.join(np.random.multinomial(numb, [1/10], size=1))
while True:
amount = int(input("How many Do you want to generate?" + "\n"))
for i in range(1,amount):
get_list()
@Samer Ayoub, answer was what I needed, just added the sep='' so it came as I expected.
import random
n, m, k= 3, 9, 14
lis = [random.choice(range(0, m)) for i in range(k)]
tot = sum(lis)
print(*lis, sep = '')
while tot%n != 0:
tot -= lis.pop()
last = random.choice(range(0, m))
lis.append(last)
tot += last
Perhaps a bit pedantic, but if anyone reading this in the future has a use-case in which questions of probability distribution matters, they should be aware that the algorithm of picking all but the last number at random and then picking the last number so as to satisfy the constraints, introduces a bias in the last number. As proof of concept:
import random, math
def f(k,a,b):
"""generates k random integers in a,b which sum to an even number"""
start = [random.randint(a,b) for _ in range(k-1)]
if sum(start) % 2 == 0:
#pick an even number
start.append(2*random.randint(math.ceil(a/2),math.floor(b/2)))
else:
#pick an off number
start.append(1 + 2*random.randint(math.ceil((a-1)/2),math.floor((b-1)/2)))
return start
For example, a typical run of f(3,1,5)
produced [1, 5, 2]
.
But:
trials = [f(3,1,5) for _ in range(10000)]
print(sum(trial[0]%2 == 0 for trial in trials)/10000) #percentage of first nums which are even
print(sum(trial[2]%2 == 0 for trial in trials)/10000) #percentage of last nums which are even
typical output:
0.3996
0.5198
Which shows a clear bias.
Generate your list fully, check if the sum is divisible by n, if not replace last element untill it works:
import random
n, m, k= 3, 9, 15
lis = [random.choice(range(0, m)) for i in range(k)]
tot = sum(lis)
while tot%n != 0:
tot -= lis.pop()
last = random.choice(range(0, m))
lis.append(last)
tot += last
An improvement on @SamerAyoub using numpy
:
import numpy as np
n, m, k= 3, 9, 15
arr = np.empty(k, dtype = int)
arr[1:] = np.random.choice(np.arange(0, m), k-1)
rem = arr[1:].sum() % n
arr[0] = np.random.choice(np.arange(n - rem, m, n))
print(''.join([str(i) for i in arr]))
print(arr.sum()%n == 0)
374564205252063
True
There's also the (not guaranteed to be especially fast, especially if n
is large) brute force method, which at least guarantees no bias (but doesn't guarantee ever finishing):
def slow_way(n, m, k):
arr = np.empty(k)
while arr.sum() % n != 0:
arr = np.random.choice(np.arange(0, m), k)
return arr
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.