Skip to content

Commit

Permalink
Add include_bounds argument to pl.Expr.is_between. (#2368)
Browse files Browse the repository at this point in the history
Add include_bounds argument to pl.Expr.is_between, which allows
to define of lower and/or upper bound should be excluded/included.
  • Loading branch information
ghuls committed Jan 14, 2022
1 parent 2c8e94b commit a9ebfe5
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 2 deletions.
36 changes: 34 additions & 2 deletions py-polars/polars/internals/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1352,10 +1352,31 @@ def repeat_by(self, by: Union["Expr", str]) -> "Expr":
return wrap_expr(self._pyexpr.repeat_by(by._pyexpr))

def is_between(
self, start: Union["Expr", datetime], end: Union["Expr", datetime]
self,
start: Union["Expr", datetime],
end: Union["Expr", datetime],
include_bounds: Union[bool, Sequence[bool]] = False,
) -> "Expr":
"""
Check if this expression is between start and end.
Parameters
----------
start
Lower bound as primitive type or datetime.
end
Upper bound as primitive type or datetime.
include_bounds
False: Exclude both start and end (default).
True: Include both start and end.
[False, False]: Exclude start and exclude end.
[True, True]: Include start and include end.
[False, True]: Exclude start and include end.
[True, False]: Include start and exclude end.
Returns
-------
Expr that evaluates to a Boolean Series.
"""
cast_to_datetime = False
if isinstance(start, datetime):
Expand All @@ -1368,7 +1389,18 @@ def is_between(
expr = self.cast(Datetime)
else:
expr = self
return ((expr > start) & (expr < end)).alias("is_between")
if include_bounds is False or include_bounds == [False, False]:
return ((expr > start) & (expr < end)).alias("is_between")
elif include_bounds is True or include_bounds == [True, True]:
return ((expr >= start) & (expr <= end)).alias("is_between")
elif include_bounds == [False, True]:
return ((expr > start) & (expr <= end)).alias("is_between")
elif include_bounds == [True, False]:
return ((expr >= start) & (expr < end)).alias("is_between")
else:
raise ValueError(
"include_bounds should be a boolean or [boolean, boolean]."
)

def hash(self, k0: int = 0, k1: int = 1, k2: int = 2, k3: int = 3) -> "Expr":
"""
Expand Down
18 changes: 18 additions & 0 deletions py-polars/tests/test_lazy.py
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,24 @@ def test_is_between(fruits_cars: pl.DataFrame) -> None:
assert fruits_cars.select(pl.col("A").is_between(2, 4))["is_between"].series_equal( # type: ignore
pl.Series("is_between", [False, False, True, False, False])
)
assert fruits_cars.select(pl.col("A").is_between(2, 4, False))["is_between"].series_equal( # type: ignore
pl.Series("is_between", [False, False, True, False, False])
)
assert fruits_cars.select(pl.col("A").is_between(2, 4, [False, False]))["is_between"].series_equal( # type: ignore
pl.Series("is_between", [False, False, True, False, False])
)
assert fruits_cars.select(pl.col("A").is_between(2, 4, True))["is_between"].series_equal( # type: ignore
pl.Series("is_between", [False, True, True, True, False])
)
assert fruits_cars.select(pl.col("A").is_between(2, 4, [True, True]))["is_between"].series_equal( # type: ignore
pl.Series("is_between", [False, True, True, True, False])
)
assert fruits_cars.select(pl.col("A").is_between(2, 4, [False, True]))["is_between"].series_equal( # type: ignore
pl.Series("is_between", [False, False, True, True, False])
)
assert fruits_cars.select(pl.col("A").is_between(2, 4, [True, False]))["is_between"].series_equal( # type: ignore
pl.Series("is_between", [False, True, True, False, False])
)


def test_drop_duplicates() -> None:
Expand Down

0 comments on commit a9ebfe5

Please sign in to comment.