#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 () не допускает дублирования элементов в последовательности.