Случайная итерация в Python

Если вы хотите последовательно перебирать список чисел, вы будете писать:

for i in range(1000):
  # do something with i

Но что, если вы хотите случайным образом перебирать список чисел из диапазона (0..999)? Существует необходимость (на каждой итерации) произвольно выбирать число, которое не было выбрано ни в одной предыдущей итерации, и необходимо перебрать все числа из диапазона (0..999).

Вы знаете, как это сделать (умный)?

Ответ 1

Вы можете использовать random.shuffle() чтобы random.shuffle() список:

import random

r = list(range(1000))
random.shuffle(r)
for i in r:
  # do something with i

Кстати, во многих случаях, когда вы используете цикл for целого ряда в других языках программирования, вы можете напрямую описать "вещь", которую вы хотите повторить в Python.
Например, если вы хотите использовать значения i для доступа к элементам списка, вам лучше лучше перетасовать список напрямую:

lst = [1970, 1991, 2012]
random.shuffle(lst)
for x in lst:
  print x

ПРИМЕЧАНИЕ: вы должны помнить следующее предупреждение при использовании random.shuffle() (взято из документации:

Обратите внимание, что даже для довольно небольших len (x) общее число перестановок x больше, чем период большинства генераторов случайных чисел; это означает, что большинство перестановок длинной последовательности никогда не могут быть сгенерированы.

Ответ 2

Люди часто пропускают возможности для модуляции. Вы можете определить функцию для инкапсуляции идеи "итерации случайным образом":

def randomly(seq):
    shuffled = list(seq)
    random.shuffle(shuffled)
    return iter(shuffled)

то

for i in randomly(range(1000)):
    #.. we're good to go ..

Ответ 3

Демонстрация генераторов Python и перемешивание Фишера-Йейтса.

import random

def shuffled(sequence):
    deck = list(sequence)
    while len(deck):
        i = random.randint(0, len(deck) - 1) # choose random card
        card = deck[i]                       # take the card
        deck[i] = deck[-1]                   # put top card in its place
        deck.pop()                           # remove top card
        yield card

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

Примечание. Если выбрана верхняя карта, deck[i] = deck.pop() будет небезопасной, поэтому удаление верхней осуществляется в два этапа.

Ответ 4

В numpy есть функция random.permutation() которая делает именно это для вас. Ваш код будет выглядеть так

from numpy.random import permutation

for i in permutation(1000):
    # do something with i

Ответ 5

Используйте метод random.shuffle:

itrange = list(range(100))
random.shuffle(itrange)
for i in itrange:
    print i

Ответ 6

Здесь другой подход к итерации списка в случайном порядке. Это не изменяет исходный список в отличие от решений, использующих shuffle()

lst=['a','b','c','d','e','f']
for value in sorted(lst,key=lambda _: random.random()):
    print value

или же:

for value in random.sample(lst,len(lst)):
    print value