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

v2.4.28 - added half_product

parent 3c95ec30
No related branches found
No related tags found
No related merge requests found
# v2.4.28 # v2.4.28
* _TBA_ * added `half_product`
# v2.4.27 # v2.4.27
......
...@@ -49,3 +49,14 @@ Sometimes you need to iterate through list and take also the next ...@@ -49,3 +49,14 @@ Sometimes you need to iterate through list and take also the next
element. element.
.. autofunction:: satella.coding.sequences.add_next .. autofunction:: satella.coding.sequences.add_next
half_cartesian
--------------
Sometimes you need just a half of your Cartesian product, for example
for operations that are commutative (eg. checking for collisions,
if object A collides with B then B collides with A).
It helps you save time during computationally intensive operations.
.. autofuction:: satella.coding.sequences.half_cartesian
__version__ = '2.4.28a1' __version__ = '2.4.28'
from .choose import choose from .choose import choose
from .iterators import infinite_counter, take_n, is_instance from .iterators import infinite_counter, take_n, is_instance
from .sequences import is_last, add_next from .sequences import is_last, add_next, half_product
__all__ = ['choose', 'infinite_counter', 'take_n', 'is_instance', 'is_last', 'add_next'] __all__ = ['choose', 'infinite_counter', 'take_n', 'is_instance', 'is_last', 'add_next',
'half_product']
...@@ -5,6 +5,7 @@ logger = logging.getLogger(__name__) ...@@ -5,6 +5,7 @@ logger = logging.getLogger(__name__)
__all__ = ['is_last'] __all__ = ['is_last']
T = tp.TypeVar('T') T = tp.TypeVar('T')
U = tp.TypeVar('U')
# shamelessly copied from https://medium.com/better-programming/is-this-the-last-element-of-my-python-for-loop-784f5ff90bb5 # shamelessly copied from https://medium.com/better-programming/is-this-the-last-element-of-my-python-for-loop-784f5ff90bb5
...@@ -49,3 +50,23 @@ def add_next(lst: tp.Iterable[T]) -> tp.Generator[tp.Tuple[T, tp.Optional[T]], N ...@@ -49,3 +50,23 @@ def add_next(lst: tp.Iterable[T]) -> tp.Generator[tp.Tuple[T, tp.Optional[T]], N
prev_val = val prev_val = val
yield prev_val, None yield prev_val, None
def half_product(seq1: tp.Iterable[T], seq2: tp.Iterable[U]) -> tp.Generator[tp.Tuple[T, U], None, None]:
"""
Generate half of the Cartesian product of both sequences.
Useful when you have a commutative operation that you'd like to execute on both elements
(eg. checking for collisions).
Example:
>>> list(half_cartesian([1, 2, 3], [1, 2, 3])) == \
>>> [(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]
:param seq1: First sequence
:param seq2: Second sequence
"""
for i, elem1 in enumerate(seq1):
for j, elem2 in enumerate(seq2):
if j >= i:
yield elem1, elem2
...@@ -2,12 +2,17 @@ import logging ...@@ -2,12 +2,17 @@ import logging
import unittest import unittest
from satella.coding.sequences import choose, infinite_counter, take_n, is_instance, is_last, \ from satella.coding.sequences import choose, infinite_counter, take_n, is_instance, is_last, \
add_next add_next, half_product
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class TestSequences(unittest.TestCase): class TestSequences(unittest.TestCase):
def test_half_product(self):
a = set(half_product([1, 2, 3], [1, 2, 3]))
b = set([(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)])
self.assertEqual(a, b)
def test_add_next(self): def test_add_next(self):
self.assertEqual(list(add_next([1, 2, 3, 4, 5])), self.assertEqual(list(add_next([1, 2, 3, 4, 5])),
[(1, 2), (2, 3), (3, 4), (4, 5), (5, None)]) [(1, 2), (2, 3), (3, 4), (4, 5), (5, None)])
......
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