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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

### New Features

- Implemented `none` function to complement the `any` and `all` boolean function
- Retrofitted `any` and `all` with a parameter so as to provide the functionality of `exists` and `for_all` respectively
- 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
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -388,11 +388,12 @@ complete documentation reference
| `count(func)` | Returns count of elements in sequence where `func(element)` is True | action |
| `empty()` | Returns `True` if the sequence has zero length | action |
| `non_empty()` | Returns `True` if sequence has non-zero length | action |
| `all()` | Returns `True` if all elements in sequence are truthy | action |
| `all(func=None)` | Returns `True` if `func(element)` is `True` for all elements in sequence or, if `func` not specified, all elements are truthy | action |
| `exists(func)` | Returns `True` if `func(element)` for any element in the sequence is `True` | action |
| `for_all(func)` | Returns `True` if `func(element)` is `True` for all elements in the sequence | action |
| `find(func)` | Returns the first element for which `func(element)` evaluates to `True` | action |
| `any()` | Returns `True` if any element in sequence is truthy | action |
| `any(func=None)` | Returns `True` if `func(element)` for any element in sequence is `True` or, if `func` not specified, any element is truthy | action |
| `none(func=None)` | Returns `True` if `func(element)` for all elements in sequence is `False` or, if `func` not specified, all elements are falsy | action |
| `max()` | Returns maximal element in sequence | action |
| `min()` | Returns minimal element in sequence | action |
| `max_by(func)` | Returns element with maximal value `func(element)` | action |
Expand Down
66 changes: 58 additions & 8 deletions functional/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -875,33 +875,83 @@ def non_empty(self) -> bool:
"""
return self.size() != 0

def any(self) -> bool:
def any(self, func: Callable[[_T_co], Any] | None = None) -> bool:
"""
Returns True if any element in the sequence has truth value True
Returns True if func on an element in the sequence evaluates to True,
or if func is not specified or None, True is returned if any element
has truth value of True.

>>> seq([1, 2, 3, 4]).any(lambda x: x == 2)
True

>>> seq([1, 2, 3, 4]).any(lambda x: x < 0)
False

>>> seq([True, False]).any()
True

>>> seq([False, False]).any()
False

:return: True if any element is True
:param func: function to check elements
:return: True if func on any element returns True,
or if func is not specified, True if any element is True
"""
return any(self)
if func is None:
return any(self)
else:
return any(func(element) for element in self)

def all(self) -> bool:
def all(self, func: Callable[[_T_co], Any] | None = None) -> bool:
"""
Returns True if the truth value of all items in the sequence true.
Returns True if func on all elements in sequence evaluates to True,
or if func is not specified or None, True is returned if all elements
have a truth value of True.

>>> seq([1, 2, 3]).all(lambda x: x > 0)
True

>>> seq([1, 2, -1]).all(lambda x: x > 0)
False

>>> seq([True, True]).all()
True

>>> seq([True, False]).all()
False

:return: True if all items truth value evaluates to True
:param func: function to check elements
:return: True if func on all elements returns True,
or if func is not specified, True if all elements are True
"""
if func is None:
return all(self)
else:
return all(func(element) for element in self)

def none(self, func: Callable[[_T_co], Any] | None = None) -> bool:
"""
Returns True if func on all elements in sequence evaluates to False,
or if func is not specified or None, True is returned if all elements
have a truth value of False.

>>> seq([-1, -2, -3]).none(lambda x: x > 0)
True

>>> seq([1, 2, -1]).none(lambda x: x > 0)
False

>>> seq([False, False]).none()
True

>>> seq([True, False]).none()
False

:param func: function to check elements
:return: True if func on all elements returns False,
or if func is not specified, True if all elements are False
"""
return all(self)
return not self.any(func)

def exists(self, func: Callable[[_T_co], Any]) -> bool:
"""
Expand Down
54 changes: 45 additions & 9 deletions functional/test/test_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,15 +530,51 @@ def test_slice(self):
self.assertIteratorEqual(result, [2, 3])
self.assert_type(result)

def test_any(self):
l = [True, False]
self.assertTrue(self.seq(l).any())

def test_all(self):
l = [True, False]
self.assertFalse(self.seq(l).all())
l = [True, True]
self.assertTrue(self.seq(l).all())
@parametrize(
"sequence, no_function",
[
(["aaa", "BBB", "ccc"], False),
([True, False], True),
],
)
def test_any(self, sequence, no_function):
if no_function:
self.assertTrue(self.seq(sequence).any())
else:
self.assertTrue(self.seq(sequence).any(str.islower))
self.assertTrue(self.seq(sequence).any(str.isupper))
self.assertFalse(self.seq(sequence).any(lambda s: "d" in s))

@parametrize(
"sequence, expected, no_function",
[
([True, False], False, True),
([True, True], True, True),
(["aaa", "bbb", "ccc"], True, False),
],
)
def test_all(self, sequence, expected, no_function):
if no_function:
self.assertEqual(expected, self.seq(sequence).all())
else:
self.assertTrue(self.seq(sequence).all(str.islower))
self.assertFalse(self.seq(sequence).all(str.isupper))

@parametrize(
"sequence, expected, no_function",
[
([False, False], True, True),
([True, False], False, True),
([True, True], False, True),
(["aaa", "bbb", "ccc"], True, False),
],
)
def test_none(self, sequence, expected, no_function):
if no_function:
self.assertEqual(expected, self.seq(sequence).none())
else:
self.assertTrue(self.seq(sequence).none(str.isupper))
self.assertFalse(self.seq(sequence).none(str.islower))

def test_enumerate(self):
l = [2, 3, 4]
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 @@ -108,6 +108,8 @@ def type_checking() -> None:

t_all: bool = seq([True, True]).all()

t_none: bool = seq([False, False]).none()

t_exists: bool = seq([1, 2, 3, 4]).exists(lambda x: x == 2)

t_for_all: bool = seq([1, 2, 3]).for_all(lambda x: x > 0)
Expand Down