Jak utworzyć listę liczb losowych bez duplikatów?

110

Próbowałem użyć random.randint(0, 100), ale niektóre liczby były takie same. Czy istnieje metoda / moduł tworzenia listy unikalnych liczb losowych?

Uwaga: Poniższy kod jest oparty na odpowiedzi i został dodany po opublikowaniu odpowiedzi. To nie jest część pytania; to jest rozwiązanie.

def getScores():
    # open files to read and write
    f1 = open("page.txt", "r");
    p1 = open("pgRes.txt", "a");

    gScores = [];
    bScores = [];
    yScores = [];

    # run 50 tests of 40 random queries to implement "bootstrapping" method 
    for i in range(50):
        # get 40 random queries from the 50
        lines = random.sample(f1.readlines(), 40);
iCodeLikeImDrunk
źródło
1
Jeśli są unikalne, mogą być naprawdę przypadkowe w odpowiednim kontekście. Podobnie jak losowa próbka indeksów bez zamiany może nadal być całkowicie losowa.
gbtimmon

Odpowiedzi:

180

Spowoduje to wyświetlenie listy 10 liczb wybranych z zakresu od 0 do 99 bez duplikatów.

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

Nawiązując do swojej przykład kodu specyficzne, prawdopodobnie chcesz, aby przeczytać wszystkie wiersze z pliku raz , a następnie wybrać losowo wiersze z listy zapisanej w pamięci. Na przykład:

all_lines = f1.readlines()
for i in range(50):
    lines = random.sample(all_lines, 40)

W ten sposób wystarczy, że faktycznie przeczytasz z pliku tylko raz, przed wykonaniem pętli. Jest to o wiele bardziej wydajne niż szukanie z powrotem na początek pliku i f1.readlines()ponowne wywoływanie dla każdej iteracji pętli.

Greg Hewgill
źródło
2
Ta technika marnuje pamięć, szczególnie w przypadku dużych próbek. Poniżej zamieściłem kod dla znacznie większej ilości pamięci i wydajnego obliczania rozwiązania, które wykorzystuje liniowy generator kongruencyjny.
Thomas Lux
Zwrócono mi uwagę, że metoda LCG jest mniej „losowa”, więc jeśli chcesz wygenerować wiele unikalnych losowych sekwencji, różnorodność będzie mniejsza niż to rozwiązanie. Jeśli potrzebujesz tylko kilku losowych sekwencji, LCG jest do zrobienia!
Thomas Lux
Dziękuję Greg, to było przydatne
N Sivaram
15

Możesz użyć funkcji shuffle z modułu losowego w następujący sposób:

import random

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

Zauważ, że metoda shuffle nie zwraca żadnej listy, jak można by się spodziewać, a jedynie tasuje listę przekazaną przez referencję.

Ricardo Murillo
źródło
Warto tutaj wspomnieć, że xrange działa tylko w Pythonie 2, a nie w Pythonie 3.
Shayan Shafiq
10

Możesz najpierw utworzyć listę liczb od ado b, gdzie ai bsą odpowiednio najmniejszymi i największymi liczbami na liście, a następnie przetasować ją algorytmem Fishera-Yatesa lub metodą Pythona random.shuffle.

ben
źródło
1
Generowanie pełnej listy indeksów to strata pamięci, szczególnie w przypadku dużych próbek. Poniżej zamieściłem kod dla znacznie większej ilości pamięci i wydajnego obliczania rozwiązania, które wykorzystuje liniowy generator kongruencyjny.
Thomas Lux
8

Rozwiązanie przedstawione w tej odpowiedzi działa, ale może stać się problematyczne z pamięcią, jeśli wielkość próby jest mała, ale populacja jest ogromna (np.random.sample(insanelyLargeNumber, 10) .).

Aby to naprawić, poszedłbym z tym:

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
inspectorG4dget
źródło
Teraz random.samplestosuje to podejście do małej liczby próbek z dużej populacji, więc ten problem z pamięcią tak naprawdę już nie istnieje. Chociaż w momencie pisania tej odpowiedzi realizacja random.shufflemogła wyglądać inaczej.
kyrill
5

Liniowy kongruencjalny generator liczb pseudolosowych

O (1) Pamięć

O (k) Operacje

Ten problem można rozwiązać za pomocą prostego liniowego generatora kongruencji . Wymaga to stałego narzutu pamięci (8 liczb całkowitych) i maksymalnie 2 * (długość sekwencji) obliczeń.

Wszystkie inne rozwiązania zużywają więcej pamięci i więcej mocy obliczeniowej! Jeśli potrzebujesz tylko kilku losowych sekwencji, ta metoda będzie znacznie tańsza. W przypadku zakresów rozmiarów N, jeśli chcesz generować w kolejności Nunikalnych ksekwencji lub więcej, polecam zaakceptowane rozwiązanie przy użyciu wbudowanych metod, random.sample(range(N),k)ponieważ zostało to zoptymalizowane w Pythonie pod kątem szybkości.

Kod

# 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

Stosowanie

Użycie tej funkcji „random_range” jest takie samo jak w przypadku każdego generatora (np. „Range”). Przykład:

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

Przykładowe wyniki

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, ...]
Thomas Lux
źródło
1
To jest bardzo fajne! Ale jestem pewien, że to naprawdę odpowiada na pytanie; powiedz, że chcę próbkować 2 wartości od 0 do 4. Bez generowania własnych prime, funkcja zwróci mi tylko 4 możliwe odpowiedzi, ponieważ valuejest to jedyna losowo wybrana rzecz z 4 możliwymi wartościami, kiedy potrzebujemy co najmniej (4 wybierz 2) = 6, (pozwalając na nielosowe porządkowanie). random_range(2,4)zwróci wartości {(1, 0), (3, 2), (2, 1), (0, 3)}, ale nigdy pary (3,1) (lub (1,3)). Czy spodziewasz się nowych, losowo generowanych dużych liczb pierwszych dla każdego wywołania funkcji?
wowserx
1
(Zakładam również, że oczekujesz, że ludzie będą tasować sekwencję po tym, jak funkcja zwróci ją, jeśli chcą losowego uporządkowania, ponieważ zamiast tego random_range(v)powraca do vunikalnych sekwencji v!)
wowserx
Całkowita prawda! Trudno jest zrównoważyć unikanie przepełnienia liczb całkowitych i generowanie wystarczającej liczby losowych sekwencji. Zaktualizowałem funkcję, aby zawierała trochę więcej losowości, ale nadal nie jest tak losowa jak v !. To zależy od tego, czy chcesz używać tej funkcji wielokrotnie. To rozwiązanie najlepiej sprawdza się, gdy generujesz z dużego zakresu wartości (gdy zużycie pamięci przez inne osoby byłoby znacznie większe). Pomyślę o tym więcej, dzięki!
Thomas Lux
4

Jeśli lista N liczb od 1 do N jest generowana losowo, to tak, istnieje możliwość, że niektóre liczby mogą się powtórzyć.

Jeśli chcesz otrzymać listę liczb od 1 do N w kolejności losowej, wypełnij tablicę liczbami całkowitymi od 1 do N, a następnie użyj tasowania Fishera-Yatesa lub Pythona random.shuffle().

Mitch Wheat
źródło
3

Jeśli potrzebujesz próbkować bardzo duże liczby, nie możesz użyć range

random.sample(range(10000000000000000000000000000000), 10)

bo rzuca:

OverflowError: Python int too large to convert to C ssize_t

Ponadto, jeśli random.samplenie można wyprodukować żądanej liczby przedmiotów ze względu na zbyt mały zakres

 random.sample(range(2), 1000)

rzuca:

 ValueError: Sample larger than population

Ta funkcja rozwiązuje oba problemy:

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

Użycie z bardzo dużymi liczbami:

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

Przykładowy wynik:

7822019936001013053229712669368
6289033704329783896566642145909
2473484300603494430244265004275
5842266362922067540967510912174
6775107889200427514968714189847
9674137095837778645652621150351
9969632214348349234653730196586
1397846105816635294077965449171
3911263633583030536971422042360
9864578596169364050929858013943

Zastosowanie, w którym zakres jest mniejszy niż liczba żądanych pozycji:

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

Przykładowy wynik:

2, 0, 1

Działa również z ujemnymi zakresami i krokami:

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

Przykładowe wyniki:

2, -8, 6, -2, -4, 0, 4, 10, -6, 8
-3, 1, 5, -1, 3
Rzemieślnik
źródło
co jeśli wygenerujesz ponad 8 miliardów liczb, prędzej czy później zobaczysz, że stanie się zbyt duże
david_adler
Ta odpowiedź ma poważną wadę w przypadku dużych próbek. Prawdopodobieństwo kolizji rośnie liniowo z każdym krokiem. Opublikowałem rozwiązanie wykorzystujące liniowy generator kongruencyjny, który ma O (1) narzut pamięci i O (k) kroki wymagane do wygenerowania k liczb. Można to rozwiązać znacznie wydajniej!
Thomas Lux
Ta odpowiedź jest zdecydowanie lepsza, jeśli chcesz wygenerować kilka losowych sekwencji w kolejności odpowiadającej długości sekwencji! Metoda LCG jest mniej „losowa”, jeśli chodzi o generowanie wielu unikalnych sekwencji.
Thomas Lux
„Ta funkcja rozwiązuje oba problemy”. Jak rozwiązuje drugi problem? Nadal nie możesz pobrać 1000 próbek z populacji 2. Zamiast rzucać wyjątek, dajesz niepoprawny wynik; to raczej nie jest rozwiązanie „problemu” (co tak naprawdę nie jest problemem na początku, ponieważ nie jest wcale rozsądne żądanie k unikalnych próbek z populacji n <k ).
kyrill
1

Możesz użyć Numpy biblioteki aby uzyskać szybką odpowiedź, jak pokazano poniżej -

Podany fragment kodu zawiera 6 unikalnych liczb z zakresu od 0 do 5. Możesz dostosować parametry dla swojej wygody.

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

Wynik

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

Nie nakłada żadnych ograniczeń, jak widzimy w przykładzie losowym, o którym mowa tutaj .

Mam nadzieję, że to trochę pomoże.

dataLeo
źródło
1

Podana tutaj odpowiedź działa bardzo dobrze w odniesieniu do czasu, a także pamięci, ale jest nieco bardziej skomplikowana, ponieważ wykorzystuje zaawansowane konstrukcje Pythona, takie jak yield. Prostsza odpowiedź sprawdza się w praktyce, ale problem z tą odpowiedzią jest to, że może generować wiele fałszywych całkowite zanim faktycznie konstruowania wymaganego zestawu. Wypróbuj z populacjąSize = 1000, sampleSize = 999. Teoretycznie istnieje szansa, że ​​to się nie zakończy.

Poniższa odpowiedź dotyczy obu kwestii, ponieważ jest deterministyczna i nieco wydajna, choć obecnie nie jest tak wydajna jak pozostałe dwie.

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

gdzie funkcje getElem, percolateUp są zdefiniowane poniżej

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

Wreszcie średni czas wynosił około 15 ms dla dużej wartości n, jak pokazano poniżej,

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]
aak318
źródło
Myślisz, że ta odpowiedź jest skomplikowana? Więc co to jest ?! Jest jeszcze druga odpowiedź , która generuje wiele „fałszywych liczb całkowitych”. Uruchomiłem twoją implementację z przykładowymi danymi wejściowymi, które podałeś (populacjaSize = 1000, sampleSize = 999). Twoja wersja wywołuje random.randintfunkcję 3996 razy, podczas gdy druga - cca. 6000 razy. Niezbyt duża poprawa, co?
kyrill
@kyrill, twoje podejście do tej odpowiedzi
aak318
1

Aby otrzymać program, który generuje listę wartości losowych bez duplikatów, który jest deterministyczny, wydajny i zbudowany z podstawowych konstrukcji programistycznych, rozważ funkcję extractSampleszdefiniowaną poniżej:

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

Podstawową ideą jest śledzenie odstępów czasu intervalLstdla możliwych wartości, z których należy wybrać nasze wymagane elementy. Jest to deterministyczne w tym sensie, że gwarantujemy wygenerowanie próbki w ramach ustalonej liczby kroków (wyłącznie w zależności od populationSizeisampleSize ).

Aby skorzystać z powyższej funkcji w celu wygenerowania naszej wymaganej listy,

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

Możemy również porównać z wcześniejszym rozwiązaniem (dla niższej wartości populacjiSize)

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

Zwróć uwagę, że zmniejszyłem populationSizewartość, ponieważ powoduje to błąd pamięci dla wyższych wartości podczas korzystania z random.samplerozwiązania (również wspomnianego w poprzednich odpowiedziach tutaj i tutaj ). W przypadku powyższych wartości możemy również zauważyć, że extractSamplesprzewyższa to random.samplepodejście.

PS: Chociaż podstawowe podejście jest podobne do mojej wcześniejszej odpowiedzi , istnieją istotne modyfikacje we wdrażaniu, a także w podejściu, wraz z poprawą przejrzystości.

aak318
źródło
0

Bardzo prosta funkcja, która również rozwiązuje Twój problem

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]

"""
Vinicius Torino
źródło
0

Problem z podejściami opartymi na zestawach („jeśli wartość losowa w zwracanych wartościach, spróbuj ponownie”) polega na tym, że ich czas działania jest nieokreślony z powodu kolizji (które wymagają kolejnej iteracji „spróbuj ponownie”), zwłaszcza gdy zwracana jest duża liczba losowych wartości z zakresu.

Alternatywą, która nie jest podatna na to niedeterministyczne środowisko wykonawcze, jest:

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]
Pomarańczowy
źródło
0
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)
user85510
źródło
1
Witamy w Stackoverflow. Proszę wyjaśnić swoją odpowiedź, dlaczego iw jaki sposób rozwiązuje problem, tak aby inni mogli łatwo ją zrozumieć.
Octobus
Chociaż ten kod może rozwiązać problem, w tym wyjaśnienie, jak i dlaczego to rozwiązuje problem, naprawdę pomogłoby poprawić jakość twojego posta i prawdopodobnie zaowocowałoby większą liczbą pozytywnych głosów. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a nie tylko osoba, która zapyta teraz. Proszę edytować swoje odpowiedzi, aby dodać wyjaśnień i dać wskazówkę co zastosować ograniczenia i założenia. Z recenzji
podwójny sygnał
-1

Jeśli chcesz mieć pewność, że dodawane liczby są unikalne, możesz użyć obiektu Set

jeśli używasz wersji 2.7 lub nowszej, lub zaimportuj moduł sets, jeśli nie.

Jak wspominali inni, oznacza to, że liczby nie są naprawdę losowe.

Recaiden
źródło
-1

do próbkowania liczb całkowitych bez zamiany między minvala 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]

z jax:

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]
grisaitis
źródło
Dlaczego miałbyś wygenerować permutaiton możliwie dużej liczby elementów, a następnie wybrać tylko pierwszy n_samplesz nich? Jakie jest Twoje uzasadnienie tego podejścia? Czy możesz wyjaśnić, jakie są zalety twojego podejścia w porównaniu z dowolną z dużej liczby istniejących odpowiedzi (większość z nich sprzed 8 lat)?
kyrill
w rzeczywistości moja odpowiedź ma podobną złożoność jak inne najczęściej głosowane odpowiedzi i jest szybsza, ponieważ używa numpy. używają innych, najczęściej wybieranych metod random.shuffle, które wykorzystują Mersenne Twister, który jest znacznie wolniejszy niż algorytmy oferowane przez numpy (i prawdopodobnie jax). numpy i jax pozwalają na inne algorytmy generowania liczb losowych. jax umożliwia także kompilację i różnicowanie w jit, co może być przydatne w przypadku różnicowania stochastycznego. również, jeśli chodzi o „prawdopodobnie dużą” tablicę, niektóre odpowiedzi random.shuffle, które
uzyskały
1
Nie jestem pewien, co masz na myśli, random.shufflemówiąc „ używa Mersenne Twister” - jest to tasowanie Fisher-Yates, jak wspomniano w kilku odpowiedziach. Ma liniową złożoność czasową, więc nie może być asymptotycznie wolniejszy niż algorytmy oferowane przez jakąkolwiek inną bibliotekę, numpy lub w inny sposób. Jeśli numpy jest szybszy, to tylko dlatego, że jest zaimplementowany w C, ale to nie gwarantuje wygenerowania ogromnej permutacji (takiej, która może nawet nie pasować do pamięci), tylko po to, aby wybrać z niej kilka elementów. Nie ma jednej odpowiedzi poza twoją, która to robi.
kyrill
Przepraszam, przeczytałem, że python losowo używał Mersenne Twister, ponieważ jest prng. Czy masz źródło, abym mógł dowiedzieć się więcej o Fisherze Yatesie i roli w random.shuffle?
grisaitis
Istnieją już dwa oddzielne linki do Wikipedii w dwóch oddzielnych odpowiedziach. Jeśli Wikipedia nie jest dla Ciebie wystarczająco dobrym źródłem, na końcu artykułu znajduje się 14 odniesień. A potem jest Google. To pomaga? Aha, i randommoduł jest napisany w Pythonie, więc możesz łatwo wyświetlić jego źródło (spróbuj random.__file__).
kyrill
-3

Z CLI w Win XP:

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

W Kanadzie mamy Lotto 6/49. Po prostu zawijam powyższy kod w lotto.bat i uruchamiam C:\home\lotto.batlub po prostuC:\home\lotto .

Ponieważ random.randintczęsto powtarza liczbę, używam setz, range(7)a następnie skracam ją do długości 6.

Czasami, jeśli liczba powtarza się więcej niż 2 razy, wynikowa długość listy będzie mniejsza niż 6.

EDYCJA: Jednak random.sample(range(6,49),6)jest to właściwy sposób.

exbctel
źródło
-3
import random
result=[]
for i in range(1,50):
    rng=random.randint(1,20)
    result.append(rng)
user2904400
źródło
1
Czy mógłbyś wyjaśnić, jak to pozwala uniknąć duplikatów? Nie jest to oczywiste z tego zrzutu kodu.
Toby Speight
Tak nie jest. print len(result), len(set(result)). Można by się spodziewać, że resultbędzie miał unikalne elementy tylko przy każdej 1.0851831788708547256608362340568947172111832359638926... × 10^20próbie.
Jedi