[英]Python - Pull random numbers from a list. Populate a new list with a specified length and sum
I am trying to create a function where:我正在尝试创建一个函数,其中:
ex.前任。 I specify that I want a list that is 4 in length and adds up to 10. random numbers are pulled from the input list until the criteria is satisfied.
我指定我想要一个长度为 4 并且加起来为 10 的列表。从输入列表中提取随机数,直到满足条件。
I feel like I am approaching this problem all wrong trying to use recursion.我觉得我尝试使用递归来解决这个问题都是错误的。 Any help will be greatly appreciated!!!
任何帮助将不胜感激!!!
EDIT: for more context on this problem.... Its going to be a random enemy generator.编辑:关于这个问题的更多背景......它将是一个随机的敌人生成器。
The end goal input list will be coming from a column in a CSV called XP.最终目标输入列表将来自一个名为 XP 的 CSV 列。 (I plan to use pandas module).
(我打算使用熊猫模块)。 But this CSV will have a list of enemy names in the one column, XP in another, Health in another, etc. So the end goal is to be able to specify the total number of enemies and what the sum XP should be between those enemies and have the list generate with the appropriate information.
但是这个 CSV 将在一列中列出敌人的名字,在另一列中列出 XP,在另一列中列出生命值,等等。所以最终目标是能够指定敌人的总数以及这些敌人之间的 XP 总和应该是多少并使用适当的信息生成列表。 For ex.
例如。 5 enemies with a total of 200 XP between them.
5 个敌人,总共 200 XP。 The result is maybe -> Apprentice Wizard(50 xp), Apprentice Wizard(50 xp), Grung(50), Xvart(25 xp), Xvart(25 xp).
结果可能是 -> Apprentice Wizard(50 xp)、Apprentice Wizard(50 xp)、Grung(50)、Xvart(25 xp)、Xvart(25 xp)。 The output list will actually need to include all of the row information for the selected items.
输出列表实际上需要包含所选项目的所有行信息。 And it is totally fine to have duplicated in the output as seen in this example.
如本例所示,在输出中进行复制是完全没问题的。 That will actually make more sense in the narrative of the game that this is for.
这实际上在游戏的叙述中更有意义。
The csv --> https://docs.google.com/spreadsheets/d/1PjnN00bikJfY7mO3xt4nV5Ua1yOIsh8DycGqed6hWD8/edit?usp=sharing csv --> https://docs.google.com/spreadsheets/d/1PjnN00bikJfY7mO3xt4nV5Ua1yOIsh8DycGqed6hWD8/edit?usp=sharing
import random
from random import *
lis = [1,2,3,4,5,6,7,8,9,10]
output = []
def query (total, numReturns, myList, counter):
random_index = randrange(len(myList)-1)
i = myList[random_index]
h = myList[i]
# if the problem hasn't been solved yet...
if len(output) != numReturns and sum(output) != total:
print(output)
# if the length of the list is 0 (if we just started), then go ahead and add h to the output
if len(output) == 0 and sum(output) + h != total:
output.append(h)
query (total, numReturns, myList, counter)
#if the length of the output is greater than 0
if len(output) > 0:
# if the length plus 1 is less than or equal to the number numReturns
if len(output) +1 <= numReturns:
print(output)
#if the sum of list plus h is greater than the total..then h is too big. We need to try another number
if sum(output) + h > total:
# start counter
for i in myList:# try all numbers in myList...
print(output)
print ("counter is ", counter, " and i is", i)
counter += 1
print(counter)
if sum(output) + i == total:
output.append(i)
counter = 0
break
if sum(output) + i != total:
pass
if counter == len(myList):
del(output[-1]) #delete last item in list
print(output)
counter = 0 # reset the counter
else:
pass
#if the sum of list plus h is less than the total
if sum(output) + h < total:
output.append(h) # add h to the list
print(output)
query (total, numReturns, myList, counter)
if len(output) == numReturns and sum(output) == total:
print(output, 'It worked')
else:
print ("it did not work")
query(10, 4, lis, 0)
I guess that it would be better to get first all n-size combinations of given array which adds to specified number, and then randomly select one of them.我想最好先获得给定数组的所有 n 大小组合,这些组合添加到指定的数字,然后随机选择其中一个。 Random selecting and checking if sum is equal to specified value, in pessimistic scenario, can last indefinitely.
随机选择并检查 sum 是否等于指定值,在悲观场景中,可以无限期持续。
from itertools import combinations as comb
from random import randint
x = [1,1,2,4,3,1,5,2,6]
def query(arr, total, size):
combs = [c for c in list(comb(arr, size)) if sum(c)==total]
return combs[randint(0, len(combs))]
#example 4-item array with items from x, which adds to 10
print(query(x, 10, 4))
If the numbers in your input list are consecutive numbers, then this is equivalent to the problem of choosing a uniform random output list of N integers in the range [min, max], where the output list is ordered randomly and min and max are the smallest and largest number in the input list.如果你的输入列表中的数字是连续的数字,那么这相当于选择一个由 [min, max] 范围内的 N 个整数组成的统一随机输出列表的问题,其中输出列表是随机排序的,min 和 max 是输入列表中的最小和最大数字。 The Python code below shows how this can be solved.
下面的 Python 代码展示了如何解决这个问题。 It has the following advantages:
它具有以下优点:
It's based on an algorithm by John McClane, which he posted as an answer to another question .它基于 John McClane 的算法,他将其发布为另一个问题的答案。 I describe the algorithm in another answer.
我在另一个答案中描述了该算法。
import random # Or secrets
def _getSolTable(n, mn, mx, sum):
t = [[0 for i in range(sum + 1)] for j in range(n + 1)]
t[0][0] = 1
for i in range(1, n + 1):
for j in range(0, sum + 1):
jm = max(j - (mx - mn), 0)
v = 0
for k in range(jm, j + 1):
v += t[i - 1][k]
t[i][j] = v
return t
def intsInRangeWithSum(numSamples, numPerSample, mn, mx, sum):
""" Generates one or more combinations of
'numPerSample' numbers each, where each
combination's numbers sum to 'sum' and are listed
in any order, and each
number is in the interval '[mn, mx]'.
The combinations are chosen uniformly at random.
'mn', 'mx', and
'sum' may not be negative. Returns an empty
list if 'numSamples' is zero.
The algorithm is thanks to a _Stack Overflow_
answer (`questions/61393463`) by John McClane.
Raises an error if there is no solution for the given
parameters. """
adjsum = sum - numPerSample * mn
# Min, max, sum negative
if mn < 0 or mx < 0 or sum < 0:
raise ValueError
# No solution
if numPerSample * mx < sum:
raise ValueError
if numPerSample * mn > sum:
raise ValueError
if numSamples == 0:
return []
# One solution
if numPerSample * mx == sum:
return [[mx for i in range(numPerSample)] for i in range(numSamples)]
if numPerSample * mn == sum:
return [[mn for i in range(numPerSample)] for i in range(numSamples)]
samples = [None for i in range(numSamples)]
table = _getSolTable(numPerSample, mn, mx, adjsum)
for sample in range(numSamples):
s = adjsum
ret = [0 for i in range(numPerSample)]
for ib in range(numPerSample):
i = numPerSample - 1 - ib
# Or secrets.randbelow(table[i + 1][s])
v = random.randint(0, table[i + 1][s] - 1)
r = mn
v -= table[i][s]
while v >= 0:
s -= 1
r += 1
v -= table[i][s]
ret[i] = r
samples[sample] = ret
return samples
Example:例子:
weights=intsInRangeWithSum(
# One sample
1,
# Count of numbers per sample
4,
# Range of the random numbers
1, 5,
# Sum of the numbers
10)
# Divide by 100 to get weights that sum to 1
weights=[x/20.0 for x in weights[0]]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.