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 `map_indexed` map function that provides both the index of the element and the element as arguments
- 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 @@ -341,6 +341,7 @@ complete documentation reference
| Function | Description | Type |
|---------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|
| `map(func)/select(func)` | Maps `func` onto elements of sequence | transformation |
| `map_indexed(func, start=0)` | Maps `func` onto elements of sequence, with each elements index starting at `start` | 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 |
Expand Down
15 changes: 15 additions & 0 deletions functional/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,21 @@ def map(self, func: Callable[[_T_co], _T]) -> Sequence[_T]:
"""
return self._transform(transformations.map_t(func))

def map_indexed(
self, func: Callable[[int, _T_co], _T], start: int = 0
) -> Sequence[_T_co | _T]:
"""
Maps func onto the elements of the sequence with each element's index as well.

>>> seq([1, 2, 3, 4]).map(lambda i, x: x * i)
[0, 2, 6, 12]

:param func: function to map with
:param start: beginning of index, zero by default
:return: sequence with func mapped onto it
"""
return self._transform(transformations.map_indexed_t(func, start))

def select(self, func: Callable[[_T_co], _T]) -> Sequence[_T]:
"""
Selects f from the elements of the sequence.
Expand Down
16 changes: 16 additions & 0 deletions functional/test/test_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,22 @@ def test_map(self):
self.assertIteratorEqual(expect, result)
self.assert_type(result)

@parametrize(
"sequence, start, expected",
[
([1, 2, 3, 4], None, [0, 2, 6, 12]),
([1, 2, 3, 4], 1, [1, 4, 9, 16]),
([], None, []),
],
)
def test_map_indexed(self, sequence, start, expected):
if start is None:
result = self.seq(sequence).map_indexed(lambda i, x: i * x)
else:
result = self.seq(sequence).map_indexed(lambda i, x: i * x, start)
self.assertIteratorEqual(expected, result)
self.assert_type(result)

def test_select(self):
l = [1, 2, 0, 5]
expect = [2, 4, 0, 10]
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 @@ -72,6 +72,8 @@ def type_checking() -> None:

t_map: Sequence[int] = seq([1, 2, 3, 4]).map(lambda x: x * -1)

t_map_indexed: Sequence[int] = seq([1, 2, 3, 4]).map_indexed(lambda i, x: x * i)

t_select: Sequence[int] = num_seq.select(lambda x: x * -1)

t_starmap: Sequence[int] = seq([(2, 3), (-2, 1), (0, 10)]).starmap(
Expand Down
19 changes: 19 additions & 0 deletions functional/transformations.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,25 @@ def map_t(func: Callable):
)


def map_indexed_t(func: Callable, start: int):
"""
Transformation for Sequence.map_indexed
:param func: map_indexed function
:param start: start of element index
:return: transformation
"""

def map_indexed(map_func, sequence):
for i, element in enumerate(sequence, start):
yield map_func(i, element)

return Transformation(
f"map_indexed({name(func)}, {start})",
partial(map_indexed, func),
None,
)


def select_t(func: Callable):
"""
Transformation for Sequence.select
Expand Down