繁体   English   中英

如何重置和洗牌“下一个”迭代器?

[英]How to reset and shuffle a "next" iterator?

我有一个 function 生成从 -180 到 180 的数字:

all_angles = list(range(-180,180))
random.shuffle(all_angles)
next_angle = iter(all_angles)

问题是它在 360 之后停止生成(这是有道理的,因为它是从 -180 到 180):

n_list = []
for i in range(1000):
    n_list.append(next(next_angle))
print(len(n_list))
>>> 360 # currently it only prints 360

一旦超过所有 360 值,我如何重置它并随机播放它? 所以上面for loop会生成 360 个打乱的数字,在遍历所有 360 个值后重置(每个值只出现一次),然后生成另一组 360 个值,依此类推。

生成器无休止地洗牌和让步:

def endless_shuffling(iterable):
    values = list(iterable)
    while True:
        random.shuffle(values)
        yield from values

而不是你的iter(all_angles) ,使用endless_shuffling(all_angles) (并删除你自己的其他洗牌)。

然后获取列表的一种方法:

random_angles = endless_shuffling(range(-180, 180))
n_list = list(islice(random_angles, 1000))

如果你给它一个空的可迭代对象并要求它提供一个值,它会“挂起”,所以要么不要这样做,要么防范这种情况(例如,使用额外的if values:或使用while values: )。

我还尝试了一种比通过生成器发送每个值更快的迭代方法,但是改组占主导地位,因此没有太大的区别:

with shuffling:
448.3 ms  endless_shuffling1
426.7 ms  endless_shuffling2

without shuffling:
 26.4 ms  endless_shuffling1
  5.1 ms  endless_shuffling2

完整代码( 在线试用! ):

from random import shuffle
from itertools import chain, islice
from timeit import default_timer as time

def endless_shuffling1(iterable):
    values = list(iterable)
    while True:
        shuffle(values)
        yield from values

def endless_shuffling2(iterable):
    values = list(iterable)
    return chain.from_iterable(iter(
        lambda: shuffle(values) or values,
        []
    ))

funcs = endless_shuffling1, endless_shuffling2

for f in funcs:
    print(*islice(f('abc'), 21))

for i in range(6):
    for f in funcs:
        t0 = time()
        next(islice(f(range(-180,180)), 999999, 1000000))
        print('%5.1f ms ' % ((time() - t0) * 1e3), f.__name__)
    print()
    if i == 2:
        print('without shuffling:\n')
        def shuffle(x):
            pass

尝试这个。 如果在调用next时收到错误,它会重新洗牌:

import random
all_angles = list(range(-180,180))
random.shuffle(all_angles)
next_angle = iter(all_angles)
n_list = []
for i in range(1000):
    try:
        n_list.append(next(next_angle))
    except StopIteration:
        random.shuffle(all_angles)
        next_angle = iter(all_angles)
        n_list.append(next(next_angle))
print(len(n_list)) # 1000

如果你想在到达终点后重新洗牌,我不知道有什么标准工具可以做到这一点。 但是您可以编写自己的可迭代对象。

import random

class Shuffler:

    def __init__(self, sequence):
        self.collection = list(sequence)
        self.reshuffle()

    def reshuffle(self):
        random.shuffle(self.collection)
        self.c_iter = iter(self.collection)

    def __iter__(self):
        return self

    def __next__(self):
        if not self.collection:
            raise StopIteration
        while True:
            try:
                return next(self.c_iter)
            except StopIteration:
                self.reshuffle()

all_angles = list(range(-180,180))
shuffler = Shuffler(all_angles)
next_angle = iter(shuffler)

n_list = []
for i in range(1000):
    n_list.append(next(next_angle))
print(len(n_list)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM