Skip to content
Snippets Groups Projects
Commit 2b5490d2 authored by Piotr Maślanka's avatar Piotr Maślanka
Browse files

added `IteratorListAdapter`

parent 5569b986
No related branches found
No related tags found
No related merge requests found
......@@ -3,3 +3,4 @@
* added `make_list`
* fixed typing issue in `choose` and `choose_one`
* added `RollingArithmeticAverage`
* added `IteratorListAdapter`
......@@ -11,6 +11,12 @@ Rolling averages
Standard routines
=================
IteratorListAdapter
-------------------
.. autoclass:: satella.coding.sequences.IteratorListAdapter
:members:
map_list
--------
......
__version__ = '2.11.10_a9'
__version__ = '2.11.10_a10'
......@@ -2,7 +2,7 @@ from .choose import choose, choose_one
from .iterators import infinite_counter, take_n, is_instance, skip_first, zip_shifted, \
stop_after, iter_dict_of_list, shift, other_sequence_no_longer_than, count, even, \
odd, n_th, smart_enumerate, smart_zip, unique, ConstruableIterator, walk, length, map_list, \
is_empty
is_empty, IteratorListAdapter
from .sequences import is_last, add_next, half_cartesian, group_quantity, Multirun, make_list
from .average import RollingArithmeticAverage
......@@ -11,4 +11,5 @@ __all__ = ['choose', 'choose_one', 'infinite_counter', 'take_n', 'is_instance',
'half_cartesian', 'skip_first', 'zip_shifted', 'stop_after', 'group_quantity',
'iter_dict_of_list', 'shift', 'other_sequence_no_longer_than', 'count', 'n_th',
'even', 'odd', 'Multirun', 'smart_enumerate', 'unique', 'map_list', 'is_empty',
'make_list', 'RollingArithmeticAverage']
'make_list', 'RollingArithmeticAverage',
'IteratorListAdapter']
......@@ -358,6 +358,58 @@ def n_th(iterator: IteratorOrIterable, n: int = 0) -> T:
raise IndexError('Iterable was too short')
class IteratorListAdapter:
"""
A wrapper around an iterator that enables it to be processed as a list.
Ie. the generator will now support __contains__, __len__ and __getitem__.
If a call to such a method is done, the generator will be unfolded in memory so this
might take a ton of memory! You've been warned!
:param iterator:
"""
__slots__ = ('unfolded', 'iterator', 'list', 'pointer')
def __init__(self, iterator: tp.Iterator):
self.iterator = iter(iterator)
self.list = None # type: list
self.unfolded = False
self.pointer = 0
def __iter__(self):
if self.unfolded:
return iter(self.list)
else:
return self
@rethrow_as(IndexError, StopIteration)
def __next__(self):
if self.unfolded:
self.pointer += 1
return self.list[self.pointer-1] # throws: IndexError
else:
return next(self.iterator)
def __unfold(self):
if self.unfolded:
return
self.list = list(self.iterator)
self.unfolded = True
self.pointer = 0
def __getitem__(self, item):
self.__unfold()
return self.list[item]
def __contains__(self, item) -> bool:
self.__unfold()
return item in self.list
def __len__(self) -> int:
self.__unfold()
return len(self.list)
def is_empty(iterable: IteratorOrIterable) -> bool:
"""
Checks whether an iterator is empty.
......
......@@ -2,11 +2,19 @@ import sys
import unittest
from satella.coding import SelfClosingGenerator, hint_with_length, chain
from satella.coding.sequences import smart_enumerate, ConstruableIterator, walk
from satella.coding.sequences import smart_enumerate, ConstruableIterator, walk, \
IteratorListAdapter
class TestIterators(unittest.TestCase):
def test_generator_list_adapter(self):
gla = IteratorListAdapter(range(10))
self.assertEqual(next(gla), 0)
self.assertEqual(gla[0], 1)
self.assertEqual(len(gla), 9)
self.assertEqual(list(gla), list(range(1, 10)))
def test_walk(self):
a = [[1, 2, 3], 4, 5, 6, [7, 8, 9]]
b = walk(a, lambda x: x if isinstance(x, list) else None, leaves_only=True)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment