Python - вытащить случайные числа из списка. Заполните новый список с указанной длиной и суммой - PullRequest
0 голосов
/ 14 марта 2020

Я пытаюсь создать функцию, где:

  1. Список вывода генерируется из случайных чисел из списка ввода
  2. Список вывода имеет указанную длину и добавляет к указанная сумма

отл. Я указываю, что мне нужен список, который имеет длину 4 и добавляет до 10. Случайные числа извлекаются из списка ввода до тех пор, пока критерии не будут удовлетворены.

Мне кажется, что я неправильно подхожу к этой проблеме, пытаясь использовать рекурсию. Любая помощь будет принята с благодарностью !!!

РЕДАКТИРОВАТЬ: для получения дополнительной информации по этой проблеме .... Это будет случайный вражеский генератор.

Будет введен список ввода конечной цели из столбца в CSV под названием XP. (Я планирую использовать модуль pandas). Но у этого CSV будет список имен врагов в одном столбце, XP в другом, Health в другом и т. Д. c. Таким образом, конечная цель состоит в том, чтобы иметь возможность указать общее количество врагов и сумму XP, которая должна быть между этими врагами, и составить список с соответствующей информацией. Например 5 противников с общим количеством очков опыта 200 между ними. Результат может быть -> Apprentice Wizard (50 xp), Apprentice Wizard (50 xp), Grung (50), Xvart (25 xp), Xvart (25 xp). На самом деле список вывода должен включать всю информацию о строках для выбранных элементов. И это совершенно нормально, если дублировать результаты, как показано в этом примере. Это на самом деле будет иметь больше смысла в описательной части игры, для которой она предназначена.

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)

Ответы [ 2 ]

1 голос
/ 14 марта 2020

Я думаю, что было бы лучше сначала получить все комбинации n-размера данного массива, которые добавляют к указанному числу, а затем случайным образом выбрать одну из них. Случайный выбор и проверка, равна ли сумма указанному значению, в сценарии pessimisti c может длиться бесконечно.

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))


0 голосов
/ 02 мая 2020

Если числа в вашем входном списке являются последовательными числами, то это эквивалентно проблеме выбора единого случайного выходного списка из N целых чисел в диапазоне [min, max], где выходной список упорядочен случайным образом, а min и max - самое маленькое и самое большое число в списке ввода. Код Python ниже показывает, как это можно решить. Он имеет следующие преимущества:

  • Он не использует выборку отбраковки.
  • Он выбирает случайным образом из всех комбинаций, которые отвечают требованиям, равномерно.

Он основан на алгоритме Джона Макклейна, который он опубликовал как ответ на другой вопрос . Я описываю алгоритм в другом ответе.

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

Пример:

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]]
...