programing

중복되지 않은 난수 목록을 만들려면 어떻게 해야 합니까?

bestprogram 2023. 6. 11. 11:04

중복되지 않은 난수 목록을 만들려면 어떻게 해야 합니까?

사용해 보았습니다.random.randint(0, 100)하지만 어떤 숫자들은 똑같았습니다.고유 난수 목록을 만드는 방법/모듈이 있습니까?

0에서 99까지의 범위에서 선택한 10개의 숫자 목록이 중복되지 않고 반환됩니다.

import random
random.sample(range(100), 10)

랜덤 모듈의 셔플 기능은 다음과 같이 사용할 수 있습니다.

import random

nums = list(range(1, 100)) # list of integers from 1 to 99
                           # adjust this boundaries to fit your needs
random.shuffle(nums)
print(nums) # <- List of unique random numbers

여기서 셔플 방법은 예상한 대로 목록을 반환하지 않으며 참조로 전달된 목록만 셔플합니다.

먼다음서숫목만수있들다습니록을자저에에서 숫자 목록을 만들 수 .ab서, 디에어a그리고.b목록에서 가장 작은 숫자와 가장 큰 숫자를 각각 입력한 다음 Fisher-Yates 알고리즘 또는 Python의 방법을 사용하여 입력합니다.

선형 합동 유사 난수 생성기

O(1) 메모리

O(k) 작업

이 문제는 간단한 선형 합동 생성기로 해결할 수 있습니다.이를 위해서는 일정한 메모리 오버헤드(정수 8개)와 최대 2*(시퀀스 길이) 계산이 필요합니다.

다른 모든 솔루션은 더 많은 메모리와 더 많은 컴퓨팅을 사용합니다!몇 개의 랜덤 시퀀스만 필요한 경우 이 방법이 훨씬 저렴해집니다. 크기 범의 경우 위▁of 경우 ▁ranges▁for의 범위에 대하여N만약 의 ,Nk-시퀀스 이상, 내장된 방법을 사용하여 승인된 솔루션을 추천합니다.random.sample(range(N),k)이것은 속도를 위해 파이썬에서 최적화되었기 때문입니다.

코드

# Return a randomized "range" using a Linear Congruential Generator
# to produce the number sequence. Parameters are the same as for 
# python builtin "range".
#   Memory  -- storage for 8 integers, regardless of parameters.
#   Compute -- at most 2*"maximum" steps required to generate sequence.
#
def random_range(start, stop=None, step=None):
    import random, math
    # Set a default values the same way "range" does.
    if (stop == None): start, stop = 0, start
    if (step == None): step = 1
    # Use a mapping to convert a standard range into the desired range.
    mapping = lambda i: (i*step) + start
    # Compute the number of numbers in this range.
    maximum = (stop - start) // step
    # Seed range with a random integer.
    value = random.randint(0,maximum)
    # 
    # Construct an offset, multiplier, and modulus for a linear
    # congruential generator. These generators are cyclic and
    # non-repeating when they maintain the properties:
    # 
    #   1) "modulus" and "offset" are relatively prime.
    #   2) ["multiplier" - 1] is divisible by all prime factors of "modulus".
    #   3) ["multiplier" - 1] is divisible by 4 if "modulus" is divisible by 4.
    # 
    offset = random.randint(0,maximum) * 2 + 1      # Pick a random odd-valued offset.
    multiplier = 4*(maximum//4) + 1                 # Pick a multiplier 1 greater than a multiple of 4.
    modulus = int(2**math.ceil(math.log2(maximum))) # Pick a modulus just big enough to generate all numbers (power of 2).
    # Track how many random numbers have been returned.
    found = 0
    while found < maximum:
        # If this is a valid value, yield it in generator fashion.
        if value < maximum:
            found += 1
            yield mapping(value)
        # Calculate the next value in the sequence.
        value = (value*multiplier + offset) % modulus

사용.

이 함수 "random_range"의 사용은 ("range"와 같은) 다른 생성기와 동일합니다.예:

# Show off random range.
print()
for v in range(3,6):
    v = 2**v
    l = list(random_range(v))
    print("Need",v,"found",len(set(l)),"(min,max)",(min(l),max(l)))
    print("",l)
    print()

샘플 결과

Required 8 cycles to generate a sequence of 8 values.
Need 8 found 8 (min,max) (0, 7)
 [1, 0, 7, 6, 5, 4, 3, 2]

Required 16 cycles to generate a sequence of 9 values.
Need 9 found 9 (min,max) (0, 8)
 [3, 5, 8, 7, 2, 6, 0, 1, 4]

Required 16 cycles to generate a sequence of 16 values.
Need 16 found 16 (min,max) (0, 15)
 [5, 14, 11, 8, 3, 2, 13, 1, 0, 6, 9, 4, 7, 12, 10, 15]

Required 32 cycles to generate a sequence of 17 values.
Need 17 found 17 (min,max) (0, 16)
 [12, 6, 16, 15, 10, 3, 14, 5, 11, 13, 0, 1, 4, 8, 7, 2, ...]

Required 32 cycles to generate a sequence of 32 values.
Need 32 found 32 (min,max) (0, 31)
 [19, 15, 1, 6, 10, 7, 0, 28, 23, 24, 31, 17, 22, 20, 9, ...]

Required 64 cycles to generate a sequence of 33 values.
Need 33 found 33 (min,max) (0, 32)
 [11, 13, 0, 8, 2, 9, 27, 6, 29, 16, 15, 10, 3, 14, 5, 24, ...]

답변에 제시된 솔루션은 작동하지만 샘플 크기가 작지만 모집단이 크면 메모리에 문제가 될 수 있습니다(예:random.sample(insanelyLargeNumber, 10)).

이 문제를 해결하려면 다음과 같이 하겠습니다.

answer = set()
sampleSize = 10
answerSize = 0

while answerSize < sampleSize:
    r = random.randint(0,100)
    if r not in answer:
        answerSize += 1
        answer.add(r)

# answer now contains 10 unique, random integers from 0.. 100

큰 해야 하는 에는 극단적큰숫표추본따하출경라는우를 사용할 수 .range

random.sample(range(10000000000000000000000000000000), 10)

왜냐하면 그것은 다음을 던집니다.

OverflowError: Python int too large to convert to C ssize_t

또한, 약만.random.sample할 수 .

 random.sample(range(2), 1000)

다음을 던집니다.

 ValueError: Sample larger than population

이 기능은 두 가지 문제를 모두 해결합니다.

import random

def random_sample(count, start, stop, step=1):
    def gen_random():
        while True:
            yield random.randrange(start, stop, step)

    def gen_n_unique(source, n):
        seen = set()
        seenadd = seen.add
        for i in (i for i in source() if i not in seen and not seenadd(i)):
            yield i
            if len(seen) == n:
                break

    return [i for i in gen_n_unique(gen_random,
                                    min(count, int(abs(stop - start) / abs(step))))]

매우 큰 숫자를 사용하는 경우:

print('\n'.join(map(str, random_sample(10, 2, 10000000000000000000000000000000))))

샘플 결과:

7822019936001013053229712669368
6289033704329783896566642145909
2473484300603494430244265004275
5842266362922067540967510912174
6775107889200427514968714189847
9674137095837778645652621150351
9969632214348349234653730196586
1397846105816635294077965449171
3911263633583030536971422042360
9864578596169364050929858013943

범위가 요청된 항목 수보다 작은 경우의 사용량:

print(', '.join(map(str, random_sample(100000, 0, 3))))

샘플 결과:

2, 0, 1

음의 범위 및 단계에서도 작동합니다.

print(', '.join(map(str, random_sample(10, 10, -10, -2))))
print(', '.join(map(str, random_sample(10, 5, -5, -2))))

샘플 결과:

2, -8, 6, -2, -4, 0, 4, 10, -6, 8
-3, 1, 5, -1, 3

1부터 N까지의 N개 숫자 리스트가 랜덤하게 생성되면 일부 숫자가 반복될 가능성이 있습니다.

1부터 N까지의 숫자 목록을 랜덤 순서로 표시하려면 1부터 N까지의 정수로 배열을 채운 다음 Fisher-Yates 셔플 또는 Python의 순서를 사용합니다.

여기 제가 만든 아주 작은 기능이 있습니다. 이것이 도움이 되기를 바랍니다!

import random
numbers = list(range(0, 100))
random.shuffle(numbers)

문제를 해결하는 매우 간단한 기능

from random import randint

data = []

def unique_rand(inicial, limit, total):

        data = []

        i = 0

        while i < total:
            number = randint(inicial, limit)
            if number not in data:
                data.append(number)
                i += 1

        return data


data = unique_rand(1, 60, 6)

print(data)


"""

prints something like 

[34, 45, 2, 36, 25, 32]

"""

한 가지 간단한 대안은 np.random을 사용하는 것입니다.아래 그림과 같이 선택 »

np.random.choice(range(10), size=3, replace=False) 

따라서 서로 다른 세 개의 정수가 생성됩니다. 예를 들어 [1, 3, 5], [2, 5, 1]...

여기에 제공된 답변은 메모리뿐만 아니라 시간 측면에서도 매우 잘 작동하지만 수율과 같은 고급 파이썬 구조를 사용하기 때문에 조금 더 복잡합니다.간단한 답은 실제로 잘 작동하지만, 그 답의 문제는 실제로 필요한 집합을 구성하기 전에 많은 가짜 정수를 생성할 수 있다는 것입니다.populationSize = 1000, sampleSize = 999를 사용하여 테스트해 보십시오.이론적으로는 종료되지 않을 가능성이 있습니다.

아래의 답변은 결정론적이고 다소 효율적이지만 현재는 다른 두 가지 문제만큼 효율적이지 않기 때문에 두 가지 문제를 모두 해결합니다.

def randomSample(populationSize, sampleSize):
  populationStr = str(populationSize)
  dTree, samples = {}, []
  for i in range(sampleSize):
    val, dTree = getElem(populationStr, dTree, '')
    samples.append(int(val))
  return samples, dTree

여기서 함수 getElem, percolateUp은 아래 정의된 대로입니다.

import random

def getElem(populationStr, dTree, key):
  msd  = int(populationStr[0])
  if not key in dTree.keys():
    dTree[key] = range(msd + 1)
  idx = random.randint(0, len(dTree[key]) - 1)
  key = key +  str(dTree[key][idx])
  if len(populationStr) == 1:
    dTree[key[:-1]].pop(idx)
    return key, (percolateUp(dTree, key[:-1]))
  newPopulation = populationStr[1:]
  if int(key[-1]) != msd:
    newPopulation = str(10**(len(newPopulation)) - 1)
  return getElem(newPopulation, dTree, key)

def percolateUp(dTree, key):
  while (dTree[key] == []):
    dTree[key[:-1]].remove( int(key[-1]) )
    key = key[:-1]
  return dTree

마지막으로, 아래와 같이 n의 큰 값에 대한 평균 타이밍은 약 15ms였습니다.

In [3]: n = 10000000000000000000000000000000

In [4]: %time l,t = randomSample(n, 5)
Wall time: 15 ms

In [5]: l
Out[5]:
[10000000000000000000000000000000L,
 5731058186417515132221063394952L,
 85813091721736310254927217189L,
 6349042316505875821781301073204L,
 2356846126709988590164624736328L]

결정론적이고 효율적이며 기본 프로그래밍으로 구축된 중복 없이 임의의 값의 목록을 생성하는 프로그램을 얻기 위해 구성은 함수를 고려합니다.extractSamples된, 래에정의됨아,됨,

def extractSamples(populationSize, sampleSize, intervalLst) :
    import random
    if (sampleSize > populationSize) :
        raise ValueError("sampleSize = "+str(sampleSize) +" > populationSize (= " + str(populationSize) + ")")
    samples = []
    while (len(samples) < sampleSize) :
        i = random.randint(0, (len(intervalLst)-1))
        (a,b) = intervalLst[i]
        sample = random.randint(a,b)
        if (a==b) :
            intervalLst.pop(i)
        elif (a == sample) : # shorten beginning of interval                                                                                                                                           
            intervalLst[i] = (sample+1, b)
        elif ( sample == b) : # shorten interval end                                                                                                                                                   
            intervalLst[i] = (a, sample - 1)
        else :
            intervalLst[i] = (a, sample - 1)
            intervalLst.append((sample+1, b))
        samples.append(sample)
    return samples

은 간격을 입니다.intervalLst필요한 요소를 선택할 수 있는 가능한 값입니다.은 우리가 입니다.populationSize그리고.sampleSize).

위의 기능을 사용하여 필요한 목록을 생성하기 위해,

In [3]: populationSize, sampleSize = 10**17, 10**5

In [4]: %time lst1 = extractSamples(populationSize, sampleSize, [(0, populationSize-1)])
CPU times: user 289 ms, sys: 9.96 ms, total: 299 ms
Wall time: 293 ms

이전 솔루션과 비교할 수도 있습니다(더 낮은 populationSize 값의 경우).

In [5]: populationSize, sampleSize = 10**8, 10**5

In [6]: %time lst = random.sample(range(populationSize), sampleSize)
CPU times: user 1.89 s, sys: 299 ms, total: 2.19 s
Wall time: 2.18 s

In [7]: %time lst1 = extractSamples(populationSize, sampleSize, [(0, populationSize-1)])
CPU times: user 449 ms, sys: 8.92 ms, total: 458 ms
Wall time: 442 ms

참고로 축소했습니다.populationSize는 ""를 할 때 더 Memory Error를 합니다.random.sample솔루션(이전 답변에서도 언급됨).위의 값에 대해, 우리는 또한 다음을 관찰할 수 있습니다.extractSamples는 성이우니다합수능을 능가합니다.random.sample접근.

추신: 핵심적인 접근 방식은 이전 답변과 유사하지만, 명확성 향상과 함께 구현 및 접근 방식에 상당한 변화가 있습니다.

세트 기반 접근 방식(반환 값의 임의 값인 경우 다시 시도)의 문제는 충돌(다른 "다시 시도" 반복이 필요함)으로 인해 런타임이 결정되지 않는다는 것입니다. 특히 많은 양의 임의 값이 범위에서 반환될 때 그렇습니다.

이러한 비결정론적 런타임이 발생하지 않는 대안은 다음과 같습니다.

import bisect
import random

def fast_sample(low, high, num):
    """ Samples :param num: integer numbers in range of
        [:param low:, :param high:) without replacement
        by maintaining a list of ranges of values that
        are permitted.

        This list of ranges is used to map a random number
        of a contiguous a range (`r_n`) to a permissible
        number `r` (from `ranges`).
    """
    ranges = [high]
    high_ = high - 1
    while len(ranges) - 1 < num:
        # generate a random number from an ever decreasing
        # contiguous range (which we'll map to the true
        # random number).
        # consider an example with low=0, high=10,
        # part way through this loop with:
        #
        # ranges = [0, 2, 3, 7, 9, 10]
        #
        # r_n :-> r
        #   0 :-> 1
        #   1 :-> 4
        #   2 :-> 5
        #   3 :-> 6
        #   4 :-> 8
        r_n = random.randint(low, high_)
        range_index = bisect.bisect_left(ranges, r_n)
        r = r_n + range_index
        for i in xrange(range_index, len(ranges)):
            if ranges[i] <= r:
                # as many "gaps" we iterate over, as much
                # is the true random value (`r`) shifted.
                r = r_n + i + 1
            elif ranges[i] > r_n:
                break
        # mark `r` as another "gap" of the original
        # [low, high) range.
        ranges.insert(i, r)
        # Fewer values possible.
        high_ -= 1
    # `ranges` happens to contain the result.
    return ranges[:-1]

저는 그것을 사용하는 것보다 꽤 빠른 방법을 찾았습니다.range기능(매우 느림), 사용하지 않음random에서 기능.python(나는 그것을 좋아하지 않습니다.random시드할 때 난수 생성기의 패턴을 반복하므로 기본 제공 라이브러리)

import numpy as np

nums = set(np.random.randint(low=0, high=100, size=150)) #generate some more for the duplicates
nums = list(nums)[:100]

이거 꽤 빠르네요.

아래와 같이 Numpy 라이브러리를 사용하여 빠른 답변을 할 수 있습니다.

지정된 코드 조각에는 0에서 5 사이의 6개의 고유 번호가 나열됩니다.편안하게 파라미터를 조정할 수 있습니다.

import numpy as np
import random
a = np.linspace( 0, 5, 6 )
random.shuffle(a)
print(a)

산출량

[ 2.  1.  5.  3.  4.  0.]

우리가 보는 것처럼 어떠한 제약도 가하지 않습니다.random.sample여기서 말하는 바와 같이

import random

sourcelist=[]
resultlist=[]

for x in range(100):
    sourcelist.append(x)

for y in sourcelist:
    resultlist.insert(random.randint(0,len(resultlist)),y)

print (resultlist)

사용해 보십시오...

import random

LENGTH = 100

random_with_possible_duplicates = [random.randrange(-3, 3) for _ in range(LENGTH)]
random_without_duplicates = list(set(random_with_possible_duplicates)) # This removes duplicates

장점

빠르고 효율적이며 읽을 수 있습니다.

발생 가능한 문제

이 방법은 중복된 경우 목록의 길이를 변경할 수 있습니다.

추가할 번호가 고유한지 확인하려면 Set 개체를 사용할 수 있습니다.

2.7 이상을 사용하는 경우에는 세트 모듈을 가져오십시오.

다른 사람들이 언급했듯이, 이것은 그 숫자들이 정말로 무작위적이지 않다는 것을 의미합니다.

원하는 숫자의 양이 무작위인 경우 다음과 같은 작업을 수행할 수 있습니다.이 경우 길이가 선택할 수 있는 가장 큰 숫자입니다.

새 난수가 이미 선택되었음을 알게 되면 카운트에서 1을 빼게 됩니다(카운트가 중복 여부를 알기 전에 추가되었기 때문에).목록에 없으면 원하는 대로 목록에 추가하여 다시 선택할 수 없습니다.

import random
def randomizer(): 
            chosen_number=[]
            count=0
            user_input = int(input("Enter number for how many rows to randomly select: "))
            numlist=[]
            #length = whatever the highest number you want to choose from
            while 1<=user_input<=length:
                count=count+1
                if count>user_input:
                    break
                else:
                    chosen_number = random.randint(0, length)
                    if line_number in numlist:
                        count=count-1
                        continue
                    if chosen_number not in numlist:
                        numlist.append(chosen_number)
                        #do what you want here

편집: 여기서 내 대답을 무시합니다.파이썬을 사용합니다.random.shuffle또는random.sample다른 답변에서 언급한 바와 같이

"minval"과 "maxval" 사이에서 대체하지 않고 정수를 샘플링하는 경우:
import numpy as np

minval, maxval, n_samples = -50, 50, 10
generator = np.random.default_rng(seed=0)
samples = generator.permutation(np.arange(minval, maxval))[:n_samples]

# or, if minval is 0,
samples = generator.permutation(maxval)[:n_samples]

잭스 포함:

import jax

minval, maxval, n_samples = -50, 50, 10
key = jax.random.PRNGKey(seed=0)
samples = jax.random.shuffle(key, jax.numpy.arange(minval, maxval))[:n_samples]

winxp의 CLI에서:

python -c "import random; print(sorted(set([random.randint(6,49) for i in range(7)]))[:6])"

캐나다에는 6/49 로또가 있습니다.저는 위의 코드를 로또로 포장할 뿐입니다.전속력으로C:\home\lotto.bat아니면 그냥C:\home\lotto.

ㅠㅠrandom.randint종종 숫자를 반복합니다, 저는 사용합니다.set와 함께range(7)그다음에 길이를 6으로 줄이세요.

경우에 따라 숫자가 2배 이상 반복될 경우 결과 목록 길이가 6보다 작을 수 있습니다.

편집: 단,random.sample(range(6,49),6)그것이 올바른 방법입니다.

언급URL : https://stackoverflow.com/questions/9755538/how-do-i-create-a-list-of-random-numbers-without-duplicates