Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

### New Features

- Implemented `filter_not_none` filter function that removes `None` from sequence
- 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
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ complete documentation reference
| `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 |
| `filter_not_none()` | Filters all None values from sequence | transformation |
| `flatten()` | Flattens sequence of lists to a single sequence | transformation |
| `flat_map(func)` | Maps `func` to each element, then merges the result to one flat sequence. `func` must return an iterable | transformation |
| `group_by(func)` | Groups sequence into `(key, value)` pairs where `key=func(element)` and `value` is from the original sequence | transformation |
Expand Down
11 changes: 11 additions & 0 deletions functional/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,17 @@ def filter_not(self, func: Callable[[_T_co], Any]) -> Sequence[_T_co]:
"""
return self._transform(transformations.filter_not_t(func))

def filter_not_none(self):
"""
Filters sequence to include only elements that are not None.

>>> seq([1, None, 2, None, 3]).filter_not_none()
[1, 2, 3]

:return: sequence with None filtered out
"""
return self.filter_not(lambda x: x is None)

def where(self, func: Callable[[_T_co], Any]) -> Sequence[_T_co]:
"""
Selects elements where func evaluates to True.
Expand Down
15 changes: 15 additions & 0 deletions functional/test/test_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,21 @@ def test_filter_not(self):
self.assertIteratorEqual(expect, result)
self.assert_type(result)

@parametrize(
"sequence, expected",
[
([1, None, 2, None, 3, None, 4, None, 5], [1, 2, 3, 4, 5]),
([None, None, 1, 2, 3, None, 4, 5, None], [1, 2, 3, 4, 5]),
([1, 2, 3, 4, 5], [1, 2, 3, 4, 5]),
([None, None, None, None, None], []),
([], []),
],
)
def test_filter_not_none(self, sequence, expected):
result = self.seq(sequence).filter_not_none()
self.assertIteratorEqual(expected, result)
self.assert_type(result)

def test_map_filter(self):
f = lambda x: x > 0
g = lambda x: x * 2
Expand Down
2 changes: 2 additions & 0 deletions functional/test/test_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ def type_checking() -> None:

t_filter_not: Sequence[int] = seq([-1, 1, -2, 2]).filter_not(lambda x: x > 0)

t_filter_not_none: Sequence[int] = seq([-1, 1, None, 2]).filter_not_none()

t_where: Sequence[int] = seq([-1, 1, -2, 2]).where(lambda x: x > 0)

t_count: int = seq([-1, -2, 1, 2]).count(lambda x: x > 0)
Expand Down