Python – как перемещаться по диапазону, начиная с случайной точки

У меня есть список категорий (1-4), и я хочу, чтобы цикл повторялся по всем ним. Но мне нужно начинать со случайной категории и обертывать ее до начала списка, если моя начальная точка была впереди списка [0].

Я смог сделать это довольно подробно, но мне интересно, есть ли более быстрый / элегантный способ. Вот что я сделал (и это работает):

def categorize(self, cat): cats = [1,2,3,4] if cat > 1: ncats = cats[:(cat-1)] cats = cats[(cat-1):] cats.extend(ncats) for c in cats: pass 

 from random import randrange cats = [1,2,3,4] i = randrange(len(cats)) for c in cats[i:]+cats[:i]: pass 

(Измененный choice для randrange согласно предложению)

Ну, вы можете уменьшить его до cats = cats[cat - 1:] + cats[:cat - 1]

Или создайте настраиваемую структуру данных, которая переопределяет ее так, что она будет циклически перемещаться по вашему списку один раз и только один раз из любой произвольной точки.

Общая идея:

 >>> cats = [1, 2, 3, 4] >>> import random >>> r = random.randrange(len(cats)) >>> for i in range(len(cats)): ... current = cats[(r+i)%len(cats)] ... print current ... 3 4 1 2 

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

 cats = [1,2,3,4] import random random.shuffle(cats) # Cats will now be in random order and can be looped normally. 

Для общего решения warp / round-robin я предлагаю что-то вроде:

 from itertools import cycle: from random import choice cats = [1,2,3,4] def warp(iterable, start): c = cycle(iterable) while c.next() is not start: pass for counter in range(len(iterable)): yield c.next() #random start part: for cat in warp(cats, choice(cats)): print cat 

Тип итеративных элементов не имеет значения, и вам не нужно проверять номер индекса, но просто используйте сам элемент!

 from random import shuffle shuffle(cats) for c in cats: loop expressions here 

Используйте оператор modulo!

 import random cats = [1,2,3,4] i = random.randint(0,3) for n in range(len(cats)): print cats[i%len(cats)] i+=1 

Это должно сделать это:

 import random cats = [1,2,3,4] start = random.choice(cats) new_order_cats = cats[cats.index(start):] + cats[:cats.index(start)] print 'new order', new_order_cats 
 >>> cats = [1,2,3,4] >>> import random >>> random.shuffle(cats) >>> cats [1, 3, 4, 2] >>> random.shuffle(cats) >>> cats [1, 4, 3, 2] 

[обновлено]

 >>> def circle_iter(items, start=0): ... l = len(items) ... for i in items: ... yield items[start] ... start += 1 ... if start == l: start = 0 ... >>> cats = [ 1, 2, 3, 4 ] >>> for cat in circle_iter(cats, 2): print cat ... 3 4 1 2 >>> for cat in circle_iter(cats, 1): print cat ... 2 3 4 1 
 import random cats = [1,2,3,4] def cycle_cats(items, start): sorted_items = items[items[start]:] + items[:items[start]] for item in sorted_items: yield item for cat in cycle_cats(cats, random.choice(cats)): print cat 

Сохраняет заказ, не заботится о длине списка кошек и ожидает, что вызывающий абонент укажет точку входа.