简体   繁体   English

需要帮助生成具有特定位数和 sum_of_digits 的随机数(Python 3.8)

[英]Need help generating a random number with specific amount of digits and sum_of_digits (Python 3.8)

I want to generate a random number with a specific amount of digits (specified by user) and those digits should have a specific sum that has been specified by the user.我想生成一个具有特定数量的数字(由用户指定)的随机数,并且这些数字应该具有用户指定的特定总和。 I have tried assigning a variable to the command random.randint(x,y) and then checking the len() and sum() of that variable if it is equal to the one specified by the user but it hasn't resulted in something useful.我尝试为命令random.randint(x,y)分配一个变量,然后检查该变量的len()sum()是否等于用户指定的变量,但没有产生任何结果有用。 The code that I have tried looks something like this:我尝试过的代码如下所示:

required_length = input()
required_sum = input()
z = random.randint(0 , 99999)
number = z
length = len(z)
sum1 = sum(int(digit) for digit in str(number))
if length == required_length and sum1 == required_sum:
     print(z)

To help if I haven't been specific enough, let's say I want to generate a number that should have 7 digits , and the sum of those 7 digits should be 7 .如果我不够具体,为了提供帮助,假设我想生成一个应该有 7 位数字的数字,而这 7 位数字的总和应该是 7 One of those random numbers should be 1121101. I hope this example helped.其中一个随机数应该是 1121101。我希望这个例子有所帮助。

See you soon all, and thanks a lot for your help.大家很快见,非常感谢您的帮助。

Simple solution简单的解决方案

You can create a list of numbers which can be generated and then use random.choice() function to choose 1 element from list.您可以创建一个可以生成的数字列表,然后使用random.choice() function 从列表中选择 1 个元素。

import random

n = int(input("Amount of digits: "))
x = int(input("Sum of digits: "))
numbers = [num for num in range(10 ** (n - 1), 10 ** n) if sum(map(int, str(num))) == x]
print(random.choice(numbers))

Fast solution快速解决方案

import random

t = []

def f(s, i):
    r = sum(map(int, s))
    if i == n:
        if r == x:
            t.append(s)
    else:
        for q in range(10) if len(s) else range(1, 10):
            if r + q <= x:
                f(s + str(q), i + 1)

n = int(input("Amount of digits: "))
x = int(input("Sum of digits: "))

f("", 0)
print(random.choice(t))

The way I would go on this would be to generate a number digit by digit as randomly as possible.我会 go 的方式是尽可能随机地逐位生成一个数字。

Each digit is picked among the allowed values given the "remaining" sum.给定“剩余”总和,从允许值中挑选每个数字。

To simplify the computation I work on lists of digits and I provide some function to convert from list of digits to integer and viceversa.为了简化计算,我处理了数字列表,并提供了一些 function 以从数字列表转换为 integer,反之亦然。 Note that for incompatible num of digits and sum value, an empty list is produced.请注意,对于不兼容的位数和总和值,会生成一个空列表。

import random


def seq_to_int(seq, base=10):
    """Convert sequence of digits to an integer."""
    result = 0
    for i, x in enumerate(reversed(seq)):
        if 0 <= x < base:
            result += x * base ** i
        else:
            msg = f"Invalid value in `seq` for given `base`"
            raise ValueError(msg)
                
    return result


def int_to_seq(n, base=10):
    """Convert an integer to a sequence of digits."""
    if n == 0:
        return [0]
    elif n < 0:
        raise ValueError("`n` must be non-negative.")
    else:
        result = []
        while n:
            result.append(n % base)
            n //= base
        return result[::-1]


def random_digits_given_sum(num_digits, sum_value, base=10):    
    digits = []
    max_digit = base - 1
    if sum_value > max_digit * num_digits:
        return digits
    sum_left = sum_value
    num_left = num_digits
    while num_left > 0:
        if sum_left > max_digit:
            min_rand = max(0, sum_left - max_digit * (num_left - 1))
            max_rand = max_digit
            digit = random.randint(min_rand, max_rand)
        elif sum_left >= 0 and num_left > 1:
            min_rand = 0
            max_rand = sum_left
            digit = random.randint(min_rand, max_rand)
        elif sum_left >= 0 and num_left == 1:
            digit = sum_left
        else:
            raise ValueError        
        digits.append(digit)
        sum_left -= digit
        num_left -= 1
    # ensure first digit is not 0
    if digits[0] == 0:
        non_zero_indices = [i for i, digit in enumerate(digits) if digit]
        i = random.choice(non_zero_indices)
        digits[0], digits[i] = digits[i], digits[0]
    # shuffle remaining digits
    shuffled = digits[1:]
    random.shuffle(shuffled)
    return digits[0:1] + shuffled

Below some code to test that it is actually working:下面是一些代码来测试它是否实际工作:

random.seed(0)
n = 2  # number of random inputs to gets
k = 4  # number of different generations
for _ in range(n):
    num_digits = random.randint(1, 16)
    sum_value = random.randint(1, num_digits * 9)
    for _ in range(k):
        digits = random_digits_given_sum(num_digits, sum_value)
        print(digits, seq_to_int(digits), sum(digits), sum(digits) == sum_value)

with the following output:使用以下 output:

[6, 8, 8, 9, 8, 8, 0, 9, 9, 9, 9, 6, 9] 6889880999969 98 True
[5, 9, 4, 7, 9, 5, 6, 9, 9, 9, 8, 9, 9] 5947956999899 98 True
[8, 1, 9, 8, 2, 9, 9, 7, 9, 9, 9, 9, 9] 8198299799999 98 True
[4, 2, 9, 7, 8, 9, 9, 9, 9, 9, 9, 9, 5] 4297899999995 98 True
[6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 4, 9, 9] 699999999999499 127 True
[4, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 9] 499999999999969 127 True
[3, 9, 9, 9, 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9] 399997999999999 127 True
[9, 7, 5, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9, 9] 975999998989999 127 True

showing that it is working as expected.表明它按预期工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM