开发者

python: how to know the index when you randomly select an element from a sequence with random.choice(seq)

开发者 https://www.devze.com 2023-03-08 03:43 出处:网络
I know very well how to select a random item from a list with random.choice(开发者_Go百科seq) but how do I know the index of that element?import random

I know very well how to select a random item from a list with random.choice(开发者_Go百科seq) but how do I know the index of that element?


import random
l = ['a','b','c','d','e']
i = random.choice(range(len(l)))
print i, l[i]


You could first choose a random index, then get the list element at that location to have both the index and value.

>>> import random
>>> a = [1, 2, 3, 4, 5]
>>> index = random.randint(0,len(a)-1)
>>> index
0
>>> a[index]
1


You can do it using randrange function from random module

import random
l = ['a','b','c','d','e']
i = random.randrange(len(l))
print i, l[i]


The most elegant way to do so is random.randrange:

index = random.randrange(len(MY_LIST))
value = MY_LIST[index]

One can also do this in python3, less elegantly (but still better than .index) with random.choice on a range object:

index = random.choice(range(len(MY_LIST)))
value = MY_LIST[index]

The only valid solutions are this solution and the random.randint solutions.

The ones which use list.index not only are slow (O(N) per lookup rather than O(1); gets really bad if you do this for each element, you'll have to do O(N^2) comparisons) but ALSO you will have skewed/incorrect results if the list elements are not unique.

One would think that this is slow, but it turns out to only be slightly slower than the other correct solution random.randint, and may be more readable. I personally consider it more elegant because one doesn't have to do numerical index fiddling and use unnecessary parameters as one has to do with randint(0,len(...)-1), but some may consider this a feature, though one needs to know the randint convention of an inclusive range [start, stop].

Proof of speed for random.choice: The only reason this works is that the range object is OPTIMIZED for indexing. As proof, you can do random.choice(range(10**12)); if it iterated through the entire list your machine would be slowed to a crawl.

edit: I had overlooked randrange because the docs seemed to say "don't use this function" (but actually meant "this function is pythonic, use it"). Thanks to martineau for pointing this out.

You could of course abstract this into a function:

def randomElement(sequence):
    index = random.randrange(len(sequence))
    return index,sequence[index]

i,value = randomElement(range(10**15))  # try THAT with .index, heh
                                        # (don't, your machine will die)
                                        # use xrange if using python2
# i,value = (268840440712786, 268840440712786)


If the values are unique in the sequence, you can always say: list.index(value)


Using randrage() as has been suggested is a great way to get the index. By creating a dictionary created via comprehension you can reduce this code to one line as shown below. Note that since this dictionary only has one element, when you call popitem() you get the combined index and value in a tuple.

import random

letters = "abcdefghijklmnopqrstuvwxyz"

# dictionary created via comprehension
idx, val = {i: letters[i] for i in [random.randrange(len(letters))]}.popitem()

print("index {} value {}" .format(idx, val))


We can use sample() method also. If you want to randomly select n elements from list

import random
l, n = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2
index_list = random.sample(range(len(l)), n)

index_list will have unique indexes.

I prefer sample() over choices() as sample() does not allow duplicate elements in a sequence.

0

精彩评论

暂无评论...
验证码 换一张
取 消