diff --git a/CHANGELOG.md b/CHANGELOG.md index c3fb0d4..6d0f3b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ ### New Features +- Implemented `map_not_none` map function that excludes from sequence elements mapped to `None` - Added `first_or_none`, a function to match `head_or_none` - Added run_test.sh script - Added [parametrize](https://pypi.org/project/parametrize/) for parameterized unit tests diff --git a/README.md b/README.md index f6c0e32..af2bfbb 100644 --- a/README.md +++ b/README.md @@ -341,6 +341,7 @@ complete documentation reference | Function | Description | Type | |---------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------| | `map(func)/select(func)` | Maps `func` onto elements of sequence | transformation | +| `map_not_none(func)` | Maps `func` onto elements of sequence, filtering out resultant `None` values | transformation | | `starmap(func)/smap(func)` | Applies `func` to sequence with `itertools.starmap` | transformation | | `filter(func)/where(func)` | Filters elements of sequence to only those where `func(element)` is `True` | transformation | | `filter_not(func)` | Filters elements of sequence to only those where `func(element)` is `False` | transformation | diff --git a/functional/pipeline.py b/functional/pipeline.py index a6ef89f..4a422e8 100644 --- a/functional/pipeline.py +++ b/functional/pipeline.py @@ -627,6 +627,18 @@ def map(self, func: Callable[[_T_co], _T]) -> Sequence[_T]: """ return self._transform(transformations.map_t(func)) + def map_not_none(self, func: Callable[[_T_co], _T]) -> Sequence[_T]: + """ + Maps func onto the elements of the sequence, returning only the non-None values. + + >>> seq([1, 2, 3, 4, 5]).map_not_none(lambda x: None if x % 2 == 0 else x * -1) + [-1, -3, -5] + + :param func: function to map with + :return: sequence with func mapped onto it excluding None values + """ + return self._transform(transformations.map_not_none_t(func)) + def select(self, func: Callable[[_T_co], _T]) -> Sequence[_T]: """ Selects f from the elements of the sequence. diff --git a/functional/test/test_functional.py b/functional/test/test_functional.py index f35e7d2..0f9fc64 100644 --- a/functional/test/test_functional.py +++ b/functional/test/test_functional.py @@ -348,6 +348,19 @@ def test_map(self): self.assertIteratorEqual(expect, result) self.assert_type(result) + @parametrize( + "sequence, expected", + [ + ([1, 2, 3, 4, 5], [-1, -3, -5]), + ], + ) + def test_map_not_none(self, sequence, expected): + result = self.seq(sequence).map_not_none( + lambda x: None if x % 2 == 0 else x * -1 + ) + self.assertIteratorEqual(expected, result) + self.assert_type(result) + def test_select(self): l = [1, 2, 0, 5] expect = [2, 4, 0, 10] diff --git a/functional/test/test_type.py b/functional/test/test_type.py index c9d0644..ca5a7ee 100644 --- a/functional/test/test_type.py +++ b/functional/test/test_type.py @@ -72,6 +72,10 @@ def type_checking() -> None: t_map: Sequence[int] = seq([1, 2, 3, 4]).map(lambda x: x * -1) + t_map_not_none: Sequence[int] = seq([1, 2, 3, 4]).map_not_none( + lambda x: x * -1 if x else x + ) + t_select: Sequence[int] = num_seq.select(lambda x: x * -1) t_starmap: Sequence[int] = seq([(2, 3), (-2, 1), (0, 10)]).starmap( diff --git a/functional/transformations.py b/functional/transformations.py index 22ac477..006065f 100644 --- a/functional/transformations.py +++ b/functional/transformations.py @@ -63,6 +63,26 @@ def select_t(func: Callable): ) +def map_not_none_t(func: Callable): + """ + Transformation for Sequence.map_not_none + :param func: map function + :return: transformation + """ + + def map_not_none(map_func, sequence): + for element in sequence: + result = map_func(element) + if result is not None: + yield result + + return Transformation( + f"map_not_none({name(func)})", + partial(map_not_none, func), + {ExecutionStrategies.PARALLEL}, + ) + + def starmap_t(func: Callable): """ Transformation for Sequence.starmap and Sequence.smap