Skip to content
Merged
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
6 changes: 4 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ on:
schedule:
- cron: "0 6 * * 1"

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }}

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- name: Set up Python
Expand All @@ -33,4 +36,3 @@ jobs:
uses: coverallsapp/github-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 2.6.0 (2024-10-17)

### Added
- The `how` function of `combine` can access the current interval if `pass_interval` is set (see [#97](https://github.com/AlexandreDecan/portion/issues/97)).



## 2.5.0 (2024-09-18)

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,7 @@ The values corresponding to intersecting keys (i.e., when the two instances over

```

The `how` function can also receive the current interval as third parameter, by enabling the `pass_interval` parameter of `.combine`.
The `combine` method also accepts a `missing` parameter. When `missing` is set, the `how` function is called even for non-intersecting keys, using the value of `missing` to replace the missing values:

```python
Expand Down
19 changes: 14 additions & 5 deletions portion/dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ def update(self, mapping_or_iterable):
for i, v in data:
self[i] = v

def combine(self, other, how, *, missing=...):
def combine(self, other, how, *, missing=..., pass_interval=False):
"""
Return a new IntervalDict that combines the values from current and
provided IntervalDict.
Expand All @@ -232,23 +232,32 @@ def combine(self, other, how, *, missing=...):
keys using the value of missing to replace the missing values. This is,
case (1) corresponds to f(x, missing) and case (2) to f(missing, y).

If pass_interval is set to True, the current interval will be passed to
the "how" function as third parameter.

:param other: another IntervalDict instance.
:param how: a function of two parameters that combines values.
:param how: a function combining two values.
:param missing: if set, use this value for missing values when calling "how".
:param pass_interval: if set, provide the current interval to the "how" function.
:return: a new IntervalDict instance.
"""
new_items = []

if not pass_interval:
_how = lambda x, y, i: how(x, y)
else:
_how = how

dom1, dom2 = self.domain(), other.domain()

if missing is Ellipsis:
new_items.extend(self[dom1 - dom2].items())
new_items.extend(other[dom2 - dom1].items())
else:
for i, v in self[dom1 - dom2].items():
new_items.append((i, how(v, missing)))
new_items.append((i, _how(v, missing, i)))
for i, v in other[dom2 - dom1].items():
new_items.append((i, how(missing, v)))
new_items.append((i, _how(missing, v, i)))

intersection = dom1 & dom2
d1, d2 = self[intersection], other[intersection]
Expand All @@ -257,7 +266,7 @@ def combine(self, other, how, *, missing=...):
for i2, v2 in d2.items():
if i1.overlaps(i2):
i = i1 & i2
v = how(v1, v2)
v = _how(v1, v2, i)
new_items.append((i, v))

return self.__class__(new_items)
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

setup(
name="portion",
version="2.5.0",
version="2.6.0",
license="LGPLv3",
author="Alexandre Decan",
url="https://github.com/AlexandreDecan/portion",
Expand All @@ -31,6 +31,7 @@
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
],
keywords="interval operation range math",
packages=find_packages(include=["portion"]),
Expand Down
11 changes: 11 additions & 0 deletions tests/test_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,17 @@ def add(x, y): return x + y
(P.openclosed(3, 4), 5)
])

def test_combine_pass_interval(self):
def how(x, y, z): return x, y, z

d1 = P.IntervalDict([(P.closed(1, 3), 1)])
d2 = P.IntervalDict([(P.closed(2, 4), 2)])

assert d1.combine(d2, how, pass_interval=True) == P.IntervalDict([
(P.closedopen(1, 2), 1),
(P.closed(2, 3), (1, 2, P.closed(2, 3))),
(P.openclosed(3, 4), 2)
])

def test_containment(self):
d = P.IntervalDict([(P.closed(0, 3), 0)])
Expand Down