From 0e08fbfa0e0a0c6464edf353980fbd29cab269de Mon Sep 17 00:00:00 2001 From: Samer Hamood Date: Sat, 4 Jan 2025 17:53:10 +0000 Subject: [PATCH 1/3] Add map_indexed function that allows for mapping with the element's index --- functional/pipeline.py | 15 +++++++++++++++ functional/test/test_functional.py | 16 ++++++++++++++++ functional/test/test_type.py | 2 ++ functional/transformations.py | 19 +++++++++++++++++++ 4 files changed, 52 insertions(+) diff --git a/functional/pipeline.py b/functional/pipeline.py index a6ef89f..b7c8ef2 100644 --- a/functional/pipeline.py +++ b/functional/pipeline.py @@ -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. diff --git a/functional/test/test_functional.py b/functional/test/test_functional.py index f35e7d2..eff3514 100644 --- a/functional/test/test_functional.py +++ b/functional/test/test_functional.py @@ -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] diff --git a/functional/test/test_type.py b/functional/test/test_type.py index c9d0644..7e6377a 100644 --- a/functional/test/test_type.py +++ b/functional/test/test_type.py @@ -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( diff --git a/functional/transformations.py b/functional/transformations.py index 22ac477..2c189dd 100644 --- a/functional/transformations.py +++ b/functional/transformations.py @@ -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 From b6cb6edd0f5c6344a7e374e82f2563d7d236636e Mon Sep 17 00:00:00 2001 From: Samer Hamood Date: Sat, 4 Jan 2025 18:08:21 +0000 Subject: [PATCH 2/3] Add map_indexed function to Transformations and Actions APIs table --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f6c0e32..9f25331 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_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 | From 383179b251e23ef10249403e112a84e2853e72d6 Mon Sep 17 00:00:00 2001 From: Samer Hamood Date: Mon, 20 Jan 2025 21:21:51 +0000 Subject: [PATCH 3/3] Add map_indexed function to CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3fb0d4..3a068ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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