Skip to content

Commit 1dfc6eb

Browse files
committed
feat(expr-ir): Support over(*partition_by)
Child of #2572
1 parent dbca5a5 commit 1dfc6eb

File tree

3 files changed

+29
-5
lines changed

3 files changed

+29
-5
lines changed

narwhals/_plan/arrow/dataframe.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def join(
152152
*,
153153
how: NonCrossJoinStrategy,
154154
left_on: Sequence[str],
155-
right_on: Sequence[str],
155+
right_on: Sequence[str] = (),
156156
suffix: str = "_right",
157157
) -> Self:
158158
left, right = self.native, other.native

narwhals/_plan/arrow/expr.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,13 +322,27 @@ def min(self, node: Min, frame: Frame, name: str) -> Scalar:
322322
return self._with_native(result, name)
323323

324324
# TODO @dangotbanned: top-level, complex-ish nodes
325-
# - [ ] `over`/`_ordered` (with partitions) requires `group_by`, `join`
326-
# - [x] `over_ordered` alone should be possible w/ the current API
327-
# - [x] `map_batches` is defined in `EagerExpr`, might be simpler here than on main
325+
# - [ ] Over
326+
# - [x] `over_ordered`
327+
# - [x] `group_by`, `join`
328+
# - [!] `over`
329+
# - [ ] `over_ordered` (with partitions)
330+
# - [ ] `map_batches`
331+
# - [x] elementwise
332+
# - [ ] scalar
328333
# - [ ] `rolling_expr` has 4 variants
329334

330335
def over(self, node: ir.WindowExpr, frame: Frame, name: str) -> Self:
331-
raise NotImplementedError
336+
expr = node.expr
337+
resolved = frame._grouper.by_irs(*node.partition_by).agg_irs(expr).resolve(frame)
338+
by_names = resolved.key_names
339+
result = (
340+
frame.select_names(*by_names)
341+
.join(resolved.evaluate(frame), how="left", left_on=by_names)
342+
.get_column(expr.meta.output_name())
343+
.native
344+
)
345+
return self._with_native(result, name)
332346

333347
def over_ordered(
334348
self, node: ir.OrderedWindowExpr, frame: Frame, name: str

narwhals/_plan/compliant/group_by.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,13 @@ class Grouped(Grouper[Resolved]):
203203
@property
204204
def _resolver(self) -> type[Resolved]:
205205
return Resolved
206+
207+
@classmethod
208+
def by_irs(cls, *by: ExprIR) -> Self:
209+
obj = cls.__new__(cls)
210+
obj._keys = by
211+
return obj
212+
213+
def agg_irs(self, *aggs: ExprIR) -> Self:
214+
self._aggs = aggs
215+
return self

0 commit comments

Comments
 (0)