python: как узнать индекс при случайном выборе элемента из последовательности с помощью random.choice (seq)

#python #random #indexing #choice

#python #Случайный #индексирование

Вопрос:

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

Комментарии:

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

Ответ №1:

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

Комментарии:

1. Такой элегантный ответ.

2. Допустимо также для random.choices(диапазон(len(l)), k = n), где n — количество случайных розыгрышей, которые вы хотите.

Ответ №2:

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

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

Ответ №3:

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

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

Ответ №4:

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

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

Это также можно сделать в python3, менее элегантно (но все же лучше, чем .index ) с помощью random.choice для объекта 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 , и может быть более читаемым. Я лично считаю это более элегантным, потому что не нужно манипулировать числовым индексом и использовать ненужные параметры, как это имеет отношение к randint(0,len(...)-1) , но некоторые могут счесть это особенностью, хотя нужно знать randint соглашение о включающем диапазоне [start, stop] .

Доказательство скорости для random.choice: единственная причина, по которой это работает, заключается в том, что range объект ОПТИМИЗИРОВАН для индексации. В качестве доказательства вы можете сделать random.choice(range(10**12)) ; если бы он повторялся по всему списку, ваша машина была бы замедлена до обхода.

редактировать: я пропустил randrange, потому что в документах, казалось, говорилось «не используйте эту функцию» (но на самом деле это означало «эта функция pythonic, используйте ее»). Спасибо martineau за указание на это.

Вы могли бы, конечно, абстрагировать это в функцию:

 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. Каким именно образом это «более элегантно», чем randint ?

2. @martineau: «и может быть более читаемым» — конечно, я немного поясню [отредактировано]

3. Хммм, кажется, что randrange(len(MY_LIST)) тогда это могло бы быть еще более элегантно (не нужно -1 или отдельно range() ) — не знаю о скорости (потому что у меня не установлен Py3), но в документах 2.7 говорится, что на самом деле это не создает объект range.

4. @martineau: спасибо, это странно. Я уже рассматривал эту функцию раньше, и документация была неоднозначной, подразумевая, что это «не то, что вы хотите в Python», поэтому я предположил, что это низкоуровневая функция (как и другие вещи, которые предоставляет модуль). По-видимому, они имели в виду, что это было «это более питоническое, чем то», или какая-то другая странная грамматическая конструкция. Это определенно не привело бы к созданию объекта range.

5. 1 для randrange версии. Я интерпретировал документы так, что это лучше, чем choice(range(start, stop, step)) потому что это фактически не создает range объект. В документах 3.2 есть примечание, которое randint(a, b) является просто псевдонимом для randrange(a, b 1) , что также, по-видимому, подразумевает предпочтение для него.

Ответ №5:

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

Комментарии:

1. К сожалению, если вы используете это для каждого элемента в массиве, это будет O(N^2) и дает очень искаженные / неправильные результаты, если какое-либо значение повторяется.

2. «если какое-либо значение повторяется …», мой ответ гласит «если значения уникальны». я ценю комментарий, но, пожалуйста, сделайте его специфичным для моего ответа, вместо того, чтобы просто копировать / вставлять свой комментарий для чужого ответа.

Ответ №6:

Использование 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))
  

Ответ №7:

Мы также можем использовать метод 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)
  

index_list будет иметь уникальные индексы.

Я предпочитаю sample() вместо choices(), поскольку sample () не допускает дублирования элементов в последовательности.