python: как узнать индекс, когда вы случайным образом выбираете элемент из последовательности с помощью random.choice (seq) - PullRequest
12 голосов
/ 25 мая 2011

Я очень хорошо знаю, как выбрать случайный элемент из списка с помощью random.choice(seq), но как мне узнать индекс этого элемента?

Ответы [ 6 ]

8 голосов
/ 25 мая 2011

Вы можете сначала выбрать случайный индекс, а затем получить элемент списка в этом месте, чтобы иметь как индекс, так и значение.

>>> import random
>>> a = [1, 2, 3, 4, 5]
>>> index = random.randint(0,len(a)-1)
>>> index
0
>>> a[index]
1
5 голосов
/ 25 мая 2011
import random
l = ['a','b','c','d','e']
i = random.choice(range(len(l)))
print i, l[i]
2 голосов
/ 04 февраля 2017

Вы можете сделать это, используя функцию randrange из random module

import random
l = ['a','b','c','d','e']
i = random.randrange(len(l))
print i, l[i]
2 голосов
/ 25 мая 2011

Самый элегантный способ сделать это - random.randrange :

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

Можно также сделать это в python3, менее элегантно (но все же лучше, чем .index) с random.choice в диапазоне объект:

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

Единственными допустимыми решениями являются это решение и решения random.randint.

Те, которые используют list.index, не только медленны (O(N) на поиск, чем O(1); становится очень плохо, если вы сделаете это для каждого элемента, вам придется делать O(N^2) сравнений), но ТАКЖЕ у вас будут искаженные / неправильные результаты, если элементы списка не уникальны.

Можно подумать, что это медленно, но оказывается, что оно немного медленнее, чем другое правильное решение random.randint, и может быть более читабельным. Лично я считаю, что это более элегантно, потому что не нужно возиться с числовым индексом и использовать ненужные параметры, как это имеет отношение к randint(0,len(...)-1), но некоторые могут считать это функцией, хотя нужно знать соглашение randint о включительный диапазон [start, stop].

Подтверждение скорости для random.choice: Единственная причина, по которой это работает, состоит в том, что объект range оптимизирован для индексации. В качестве доказательства вы можете сделать random.choice(range(10**12)); если он будет перебирать весь список, ваша машина будет замедлена до сканирования.

edit: я пропустил 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)
1 голос
/ 25 мая 2011

Если значения уникальны в последовательности, вы всегда можете сказать: list.index(value)

0 голосов
/ 27 мая 2017

Использование randrage () , как было предложено, является отличным способом получить индекс. Создав словарь, созданный с помощью compreatsion , вы можете уменьшить этот код до одной строки, как показано ниже. Обратите внимание, что поскольку в этом словаре есть только один элемент, при вызове 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))
...