diff --git a/CHANGELOG.md b/CHANGELOG.md index 253ea4443763e1534110814692e03d0de4bdfae2..8ba070f121b36d50ab96df17c970292e77512aaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,3 @@ # v2.14.40 + +* added `append_sequence` diff --git a/satella/__init__.py b/satella/__init__.py index 973185cdb2ba74938ab1e9f6ff1418ae933619f3..f8711d7f472e47b8c235174f8c720e8ade833ba9 100644 --- a/satella/__init__.py +++ b/satella/__init__.py @@ -1 +1 @@ -__version__ = '2.14.40a1' +__version__ = '2.14.40' diff --git a/satella/coding/sequences/__init__.py b/satella/coding/sequences/__init__.py index b484e4cc954ac662382f186676afa526f12d073f..b6a6b0961d54b597ee58ed9128adc3f82e09f52e 100644 --- a/satella/coding/sequences/__init__.py +++ b/satella/coding/sequences/__init__.py @@ -4,7 +4,7 @@ from .iterators import infinite_counter, take_n, is_instance, skip_first, zip_sh 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, IteratorListAdapter, enumerate2, to_iterator, ListWrapperIterator, try_close, \ - f_range, iterate_callable, AlreadySeen + f_range, iterate_callable, AlreadySeen, append_sequence from .sequences import is_last, add_next, half_cartesian, group_quantity, Multirun, make_list, \ infinite_iterator, filter_out_false, filter_out_nones, index_of, index_of_max @@ -16,4 +16,4 @@ __all__ = ['choose', 'choose_one', 'infinite_counter', 'take_n', 'is_instance', 'make_list', 'RollingArithmeticAverage', 'index_of', 'index_of_max', 'IteratorListAdapter', 'enumerate2', 'infinite_iterator', 'to_iterator', 'filter_out_false', 'filter_out_nones', 'ListWrapperIterator', 'try_close', - 'f_range', 'iterate_callable', 'AlreadySeen'] + 'f_range', 'iterate_callable', 'AlreadySeen', 'append_sequence'] diff --git a/satella/coding/sequences/iterators.py b/satella/coding/sequences/iterators.py index 3ad8538a01efd60b9166906bf87078dbfca136d5..ab63685f331048365d4afb4c03c444f01356ddb4 100644 --- a/satella/coding/sequences/iterators.py +++ b/satella/coding/sequences/iterators.py @@ -90,6 +90,27 @@ def f_range(*args: float) -> tp.Iterator[float]: return iterate(start, stop, step) +def append_sequence(seq: tp.Iterator[tuple], *elems_to_append) -> tp.Iterator[tuple]: + """ + Return an iterator which append elem_to_append to every tuple in seq. + + Example: + + >>> a = [(1, ), (2, ), (3, )] + >>> assert list(append_sequence(a, 1, 2)) == [(1, 1, 2), (2, 1, 2), (3, 1, 2)] + + If every element of seq is not a tuple, it will be cast to one. + + :param seq: sequence to append + :param elems_to_append: element(s) to append + :return: an iterator + """ + for tpl in seq: + if not isinstance(tpl, tuple): + tpl = tuple(tpl) + yield tpl + elems_to_append + + def walk(obj: T, child_getter: tp.Callable[[T], tp.Optional[tp.List[T]]] = list, deep_first: bool = True, leaves_only: bool = False) -> tp.Iterator[T]: diff --git a/tests/test_coding/test_sequences.py b/tests/test_coding/test_sequences.py index 8a531712c56ed61218a42fb39e4d8805f0c105a5..042eb4a9bc8438573bdda35db723405d6238e968 100644 --- a/tests/test_coding/test_sequences.py +++ b/tests/test_coding/test_sequences.py @@ -6,12 +6,17 @@ from satella.coding.sequences import choose, choose_one, infinite_counter, take_ iter_dict_of_list, shift, other_sequence_no_longer_than, count, even, odd, Multirun, n_th, \ unique, length, map_list, smart_zip, is_empty, make_list, RollingArithmeticAverage, \ enumerate2, infinite_iterator, to_iterator, filter_out_false, filter_out_nones, \ - index_of, index_of_max, try_close, f_range, iterate_callable, AlreadySeen + index_of, index_of_max, try_close, f_range, iterate_callable, AlreadySeen, \ + append_sequence from satella.coding.predicates import x class TestSequences(unittest.TestCase): + def test_append_sequence(self): + a = [(1,), (2,), (3,)] + self.assertEqual(list(append_sequence(a, 1, 2)), [(1, 1, 2), (2, 1, 2), (3, 1, 2)]) + def test_already_seen(self): as_ = AlreadySeen() self.assertTrue(as_.is_unique(1))