python:当您使用random.choice(seq)从序列中随机选择一个元素时,如何知道索引

python:当您使用random.choice(seq)从序列中随机选择一个元素时,如何知道索引,python,random,indexing,choice,Python,Random,Indexing,Choice,我很清楚如何从带有随机选择的列表中选择一个随机项,但是我如何知道该元素的索引呢?如果值在序列中是唯一的,你可以说:list.index(value)你可以先选择一个随机索引,然后在该位置获取列表元素,使其同时具有索引和值 >>> import random >>> a = [1, 2, 3, 4, 5] >>> index = random.randint(0,len(a)-1) >>> index 0 >>&g

我很清楚如何从带有随机选择的列表中选择一个随机项,但是我如何知道该元素的索引呢?

如果值在序列中是唯一的,你可以说:
list.index(value)
你可以先选择一个随机索引,然后在该位置获取列表元素,使其同时具有索引和值

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

最优雅的方法是随机。随机范围:

index = random.randrange(len(MY_LIST))
value = MY_LIST[index]
你也可以在python3中使用random来实现这一点,使用range对象选择

index = random.choice(range(len(MY_LIST)))
value = MY_LIST[index]
唯一有效的解决方案是此解决方案和
random.randint
解决方案

使用
list.index
的不仅每次查找都很慢(
O(N)
,而不是
O(1)
;如果对每个元素执行此操作,就会变得非常糟糕,必须进行
O(N^2)
比较),而且如果列表元素不是唯一的,结果也会扭曲/不正确

有人可能会认为这很慢,但事实证明它只比另一个正确的解决方案random.randint稍微慢一点,并且可能更具可读性。我个人认为它更优雅,因为一个人不必做数字索引篡改和使用不必要的参数作为一个与<代码> RANTET(0,LEN(…)-1)< /C> >,但有些人可以认为这是一个特性,尽管需要知道包含代码范围>代码> > [开始,停止] < /代码> < < /P> random.choice的速度证明:唯一有效的原因是
范围
对象针对索引进行了优化。作为证明,您可以进行
随机选择(范围(10**12))
;如果它遍历整个列表,您的机器将慢到爬行

编辑:我忽略了randrange,因为文档似乎说“不要使用这个函数”(但实际上意思是“这个函数是pythonic的,使用它”)。感谢马蒂诺指出这一点

当然,您可以将其抽象为一个函数:

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)
您可以使用random模块中的randrange函数来实现

按照建议使用randrage(),这是获取索引的好方法。通过创建通过创建的字典,可以将此代码缩减为一行,如下所示。请注意,由于此字典只有一个元素,因此当调用popitem()时,将得到元组中的组合索引和值

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))
我们也可以使用sample()方法。 若要从列表中随机选择n个元素

import random
l, n = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2
index_list = random.sample(range(len(l)), n)
索引列表将具有唯一的索引


我更喜欢sample()而不是choices(),因为sample()不允许序列中有重复的元素。

另一种可能是随机选择索引,然后按索引访问序列。不幸的是,如果在数组中的每个元素上都使用它,它将是
O(N^2)
,如果任何值重复,则会给出非常扭曲/不正确的结果。“如果任何值重复…”,我的回答是“如果值是唯一的”。我很欣赏你的评论,但请针对我的回答,而不是仅仅复制/粘贴你的评论以获得其他人的答案。这比
randint
“更优雅”的确切方式是什么?@martineau:“可能更具可读性”-当然,我会澄清一点[编辑]嗯,看起来像
randrange(len(我的列表))
可能更优雅(不需要
-1
或单独的
range()
)--虽然我不知道速度(因为我没有安装Py3),但2.7文档说它实际上没有构建range对象。@martineau:谢谢,这很奇怪。我以前看过这个函数,文档不明确,暗示它“不是Python中所需要的”,所以我假设它是一个低级函数(与模块公开的其他内容一样)。显然,他们的意思是“这比那更像蟒蛇”,或者其他一些奇怪的语法结构。它肯定不会构建范围对象。
randrange
版本为+1。我对文档的解释是,它比
选择(范围(开始、停止、步骤))
更好,因为它实际上没有构建
范围
对象。在3.2文档中,有一点值得注意,
randint(a,b)
只是
randrange(a,b+1)
的别名,这似乎也暗示了对它的偏好。这是一个优雅的答案。对random.choices(range(len(l)),k=n也有效,其中n是您想要的随机绘制数。
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))
import random
l, n = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2
index_list = random.sample(range(len(l)), n)