How do I create a list of random numbers without d

2019-01-03 05:48发布

I tried using random.randint(0, 100), but some numbers were the same. Is there a method/module to create a list unique random numbers?

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

标签: python random
14条回答
smile是对你的礼貌
2楼-- · 2019-01-03 06:35

You can use Numpy library for quick answer as shown below -

Given code snippet lists down 6 unique numbers between the range of 0 to 5. You can adjust the parameters for your comfort.

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

Output

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

It doesn't put any constraints as we see in random.sample as referred here.

Hope this helps a bit.

查看更多
何必那么认真
3楼-- · 2019-01-03 06:38

The solution presented in this answer works, but it could become problematic with memory if the sample size is small, but the population is huge (e.g. random.sample(insanelyLargeNumber, 10)).

To fix that, I would go with this:

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
查看更多
爱情/是我丢掉的垃圾
4楼-- · 2019-01-03 06:40
import random
result=[]
for i in range(1,50):
    rng=random.randint(1,20)
    result.append(rng)
查看更多
淡お忘
5楼-- · 2019-01-03 06:44

So, I realize this post is 6 years old, but there is another answer with (usually) better algorithmic performance, although less practical with larger overhead.

Other answers include the shuffle method and the 'try until valid' method using sets.

If we're randomly choosing K integers without replacement from the interval 0...N-1, then the shuffle method uses O(N) storage and O(N) operations, which is annoying if we are choosing small K from large N. The set method only uses O(K) storage, but has worst case O(inf) expected O(n*log(n)) for K close to N. (Imagine trying to randomly get the last number out of two allowed answers, having already selected 999998, for k=n-1=10^6).

So the set method is fine for K~1, and the shuffle method is fine for K~N. Both use expected >K RNG calls.

Another way; you can pretend to do the Fisher–Yates shuffle, and for every new random selection, perform a binary search operation on your already-selected elements to find the value that you would get if you were actually storing an array of all the elements you haven't chosen yet.

If your already-selected values are [2,4], and your random number generator spits out 2 in the interval (N - num_already_selected), then you pretend to select out of [0,1,3,5,6,...] by counting the values less than the answer that have already been selected. In this case, your third selected value would be 3. Then, in the next step, if your random number were 2 again, it would map to 5 (in the pretend list [0,1,5,6]), because the (potential index of 5 in the sorted list of already-selected values [2,3,4], which is 3) + 2 = 5.

So store the already-selected values in a balanced binary search tree, store the rank (number of values less than that value) at each node, select a random number R from the range (0... n-(number already chosen)). Then descend the tree as if searching, but your search value is R plus the rank of whatever node you are at. When you reach a leaf node, add the random number to the rank of that node, and insert the sum into the balanced binary tree.

Once you have K elements, read them off the tree into an array and shuffle (if order is important).

This takes O(K) storage, O(K*log(K)) performance, and exactly K randint calls.

Example implementation of random sampling (non-random final ordering but you can O(K) shuffle after), O(k) storage and O(klog^2(k)) performance (not O(klog(k)) because we can't custom-descend balanced binary trees for this implementation):

from sortedcontainers import SortedList


def sample(n, k):
    '''
    Return random k-length-subset of integers from 0 to n-1. Uses only O(k) 
    storage. Bounded k*log^2(k) worst case. K RNG calls. 
    '''
    ret = SortedList()
    for i in range(k):
        to_insert = random.randint(0, n-1 - len(ret))
        to_insert = binsearch_adding_rank(ret, to_insert)
        ret.add(to_insert)

    return ret

def binsearch_adding_rank(A, v):
    l, u = 0, len(A)-1
    m=0
    while l <= u:
        m = l+(u-l)//2
        if v + m >= A[m]:
            l = m+1
            m+=1 # We're binary searching for partitions, so if the last step was to the right then add one to account for offset because that's where our insert would be.
        elif v+m < A[m]:
            u = m-1
    return v+m

And to show validity:

If we were doing the fisher-yates shuffle, having already chosen [1,4,6,7,8,9,15,16], with random number 5, our yet-to-be-chosen array would look like [0,2,3,5,10,11,12,...], so element 5 is 11. Thus our binsearch-function should return 11, given 5 and [1,4,6,7,8,9,15,16]:

assert binsearch_adding_rank([1,4,6,7,8,9,15,16], 5) == 11

Inverse of [1,2,3] is [0,4,5,6,7,8,...], the 5th element of which is 8, so:

assert binsearch_adding_rank([1,2,3], 5) == 8

Inverse of [2,3,5] is [0,1,4,6,...], the 1st element of which is (still) 1, so:

assert binsearch_adding_rank([2,3,5], 1) == 1

Inverse is [0,6,7,8,...], 3rd element is 8, and:

assert binsearch_adding_rank([1,2,3,4,5,10], 3) == 8

And to test the overall function:

# Edge cases: 
assert sample(50, 0) == []
assert sample(50, 50) == list(range(0,50))

# Variance should be small and equal among possible values:
x = [0]*10
for i in range(10_000):
    for v in sample(10, 5):
        x[v] += 1
for v in x:
    assert abs(5_000 - v) < 250, v
del x

# Check for duplication: 

y = sample(1500, 1000)
assert len(frozenset(y)) == len(y)
del y

In practice, though, use the shuffle method for K ~> N/2 and the set method for K ~< N/2.

edit: Here's another way of doing it using recursion! O(k*log(n)) I think.

def divide_and_conquer_sample(n, k, l=0):
    u = n-1
    # Base cases:
    if k == 0:
        return []
    elif k == n-l:
        return list(range(l, n))
    elif k == 1:
        return [random.randint(l, u)]

    # Compute how many left and how many right:
    m = l + (u-l)//2
    k_right = 0
    k_left = 0
    for i in range(k):
        # Base probability: (# of available values in right interval) / (total available values)
        if random.random() <= (n-m - k_right)/(n-l-k_right-k_left):
            k_right += 1
        else:
            k_left += 1
    # Recur
    return divide_and_conquer_sample(n, k_right, m) + divide_and_conquer_sample(m, k_left, l)
查看更多
不美不萌又怎样
6楼-- · 2019-01-03 06:44

A very simple function that also solves your 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]

"""
查看更多
何必那么认真
7楼-- · 2019-01-03 06:48

You can use the shuffle function from the random module like this:

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

Note here that the shuffle method doesn't return any list as one may expect, it only shuffle the list passed by reference.

查看更多
登录 后发表回答