90774


以下のサイトを参考に、イテレータを複数のイテレータに分割する関数を作成しました。  
[PythonでiterableをN個づつに分割する関数](https://qiita.com/22C8/items/2c9fd1cae4751252793c)  
サイトに記載の通りの実行結果が得られました。  
さらにnext関数の呼び出す順番を変更したところ、  
前のイテレータが破棄(StopIterationが発生する状態)されることが分かりました。  
それぞれのイテレータが、他のイテレータの影響を受けないようにすることは可能でしょうか？  
なぜ次のイテレータ(次の塊)を利用すると、前のイテレータ(前の塊)が破棄されるのでしょうか。

[code]

    import itertools
    from collections.abc import Iterable
    
    
    def split_iter(iterable: Iterable, chunksize: int):
        """iterableをＮ個づつに分割する"""
        def divide(index_value: tuple) -> int:
            return index_value[0] // chunksize  # インデックス部を整数除算
    
        for index, index_value_iter in itertools.groupby(enumerate(iterable), divide):
            yield (index_value[1] for index_value in index_value_iter)  # 値部を戻す
    
    
    print('--- 想定内の利用方法')
    it = split_iter([10, 20, 30, 40], 3)  # ３個ずつで分割
    iter_a = next(it)
    print(next(iter_a), next(iter_a), next(iter_a))
    
    iter_b = next(it)
    print(next(iter_b))
    # print(next(iter_b))  # ←もう一度nextするとStopIteration例外が発生する。（期待どおり）
    
    
    
    print('--- 異なる順番で利用した場合')
    it = split_iter([10, 20, 30, 40], 3)  # ３個ずつで分割
    iter_a = next(it)
    print(next(iter_a))
    print(next(iter_a))
    
    iter_b = next(it)
    print(next(iter_b))
    
    print(next(iter_a))  # StopIteration例外が発生する。ここでnextを呼び出しても、値30を取得できるようにしたい。
    
[/code]

以下、実行結果です。

[code]

    --- 想定内の利用方法
    10 20 30
    40
    --- 異なる順番で利用した場合
    10
    20
    40
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    セル77 を /home/sasaki/workspace/orcas_proj/jupyter_proj/orcas.ipynb in <cell line: 34>()
         31 iter_b = next(iter)
         32 print(next(iter_b))
    ---> 34 print(next(iter_a))
    
    StopIteration: 
    
[/code]


CC BY-SA 4.0
2022-08-25T11:18:44.873
90754
2022-08-27T07:38:22.910
2022-08-27T07:38:22.910
35267
35267
question
python python3
分割したIteratorを利用する順番に制約ができる


<https://docs.python.org/ja/3/library/itertools.html#itertools.groupby>  
groupbyのドキュメントに明記してあります。

> もととなる iterable を共有しているため、 groupby()
> オブジェクトの要素取り出しを先に進めると、それ以前の要素であるグループは見えなくなってしまいます。従って、データが後で必要な場合にはリストの形で保存しておく必要があります

単純には、ドキュメントに従ってリストの形で保存しておいて

[code]

    def split_iter(iterable: Iterable, chunksize: int):
        """iterableをＮ個づつに分割する"""
        def divide(index_value: tuple) -> int:
            return index_value[0] // chunksize  # インデックス部を整数除算
    
        for index, index_value_iter in itertools.groupby(enumerate(iterable), divide):
            yield iter([index_value[1] for index_value in index_value_iter])  # 値部をリストに確保してからイテレータを戻す
    
[/code]

でいいでしょう。

* * *
[code]

    >>> def split_iter(iterable: Iterable, chunksize: int):
    ...     """iterableをＮ個づつに分割する"""
    ...     def divide(index_value: tuple) -> int:
    ...         return index_value[0] // chunksize  # インデックス部を整数除算
    ...
    ...     for index, index_value_iter in itertools.groupby(enumerate(iterable), divide):
    ...         yield iter([index_value[1] for index_value in index_value_iter])  # 値部をリストに確保してからイテレータを戻す
    
    >>> it = split_iter([10, 20, 30, 40], 3)  # ３個ずつで分割 (標準関数iterを変数名に使ってはいけません)
    ... iter_a = next(it)
    ... print(next(iter_a))
    ... print(next(iter_a))
    ...
    ... iter_b = next(it)
    ... print(next(iter_b))
    ...
    ... print(next(iter_a))
    10
    20
    40
    30
    
[/code]


CC BY-SA 4.0
2022-08-26T13:06:53.487
90774
2022-08-26T13:06:53.487
12274
90754
answer