중복되지 않은 난수 목록을 만들려면 어떻게 해야 합니까?
사용해 보았습니다.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
여기서 셔플 방법은 예상한 대로 목록을 반환하지 않으며 참조로 전달된 목록만 셔플합니다.
먼다음서숫목만수있들다습니록을자저에에서 숫자 목록을 만들 수 .a
b
서, 디에어a
그리고.b
목록에서 가장 작은 숫자와 가장 큰 숫자를 각각 입력한 다음 Fisher-Yates 알고리즘 또는 Python의 방법을 사용하여 입력합니다.
선형 합동 유사 난수 생성기
O(1) 메모리
O(k) 작업
이 문제는 간단한 선형 합동 생성기로 해결할 수 있습니다.이를 위해서는 일정한 메모리 오버헤드(정수 8개)와 최대 2*(시퀀스 길이) 계산이 필요합니다.
다른 모든 솔루션은 더 많은 메모리와 더 많은 컴퓨팅을 사용합니다!몇 개의 랜덤 시퀀스만 필요한 경우 이 방법이 훨씬 저렴해집니다. 크기 범의 경우 위▁of 경우 ▁ranges▁for의 범위에 대하여N
만약 의 ,N
k
-시퀀스 이상, 내장된 방법을 사용하여 승인된 솔루션을 추천합니다.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
다른 답변에서 언급한 바와 같이
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
'programing' 카테고리의 다른 글
npm에서 Firebase를 사용하여 배포하는 중 오류 발생 -- 접두사 $RESOURCE_DIR 런 린트 (0) | 2023.06.11 |
---|---|
빈 셀이 포함된 Excel 스프레드시트를 읽기 위해 NPOI를 사용하는 방법은 무엇입니까? (0) | 2023.06.11 |
add_filter 대 add_action의 차이 (0) | 2023.06.11 |
Excel 테이블 구조화된 참조를 사용하여 실행 합계를 만드는 방법은 무엇입니까? (0) | 2023.06.11 |
R 단위로 함수 실행 시간 측정 (0) | 2023.06.06 |