Skip to content

Conversation

dsprenkels
Copy link
Collaborator

@dsprenkels dsprenkels commented Oct 15, 2025

List of all changes

  • Add Expr.item() to select the only item from an Expr. In other words: it is like Expr.first() but it will raise an error if Expr does not contain a single value
  • Add List.item(), for lists
  • Add DataFrame.item() on dataframes
  • Add Series.item() on series
  • Deprecate DataFrame.item() in favor of DataFrame.single() and DataFrame[row, col]
  • Deprecate Series.item() in favor of Series.single() and Series[index]

Review suggestions

  • Is single the correct name? Or should we consider another name?
    • Keeping the name item()
  • Are all implementations covered in the tests?

Still Todo

  • Add a note to the Expr.item docs that it does not take arguments, and that if the user wants item retrieval, they should use Expr.get

Fixes: #8689
Fixes: #21856
Related issue: #24475

@dsprenkels dsprenkels changed the title Add Expr.single to strictly extract a single value from an expression feat: Add Expr.single to strictly extract a single value from an expression Oct 15, 2025
@github-actions github-actions bot added enhancement New feature or an improvement of an existing feature python Related to Python Polars rust Related to Rust Polars and removed title needs formatting labels Oct 15, 2025
Traceback (most recent call last):
... ComputeError: cannot unpack single value from list of length 2
"""
return wrap_expr(self._pyexpr.list_single())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think list.single() can be implemented with the same perf as list.agg(pl.element().single()).

@cmdlineluser
Copy link
Contributor

Also fixes #21856 (the list variant)

@ritchie46
Copy link
Member

If we decide to go with single, I think we should rename DataFrame.item as well. Or this should be called item. Not sure yet.

@codecov
Copy link

codecov bot commented Oct 15, 2025

Codecov Report

❌ Patch coverage is 90.84507% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.82%. Comparing base (43a10fe) to head (2d0f941).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
.../polars-python/src/lazyframe/visitor/expr_nodes.rs 0.00% 4 Missing ⚠️
crates/polars-expr/src/reduce/first_last.rs 96.66% 3 Missing ⚠️
crates/polars-core/src/frame/group_by/mod.rs 0.00% 2 Missing ⚠️
crates/polars-plan/src/dsl/expr/mod.rs 0.00% 1 Missing ⚠️
crates/polars-plan/src/dsl/format.rs 0.00% 1 Missing ⚠️
...n/src/plans/conversion/dsl_to_ir/expr_expansion.rs 87.50% 1 Missing ⚠️
crates/polars-plan/src/plans/visitor/expr.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #24888      +/-   ##
==========================================
+ Coverage   81.76%   81.82%   +0.05%     
==========================================
  Files        1700     1700              
  Lines      233868   234045     +177     
  Branches     2997     2997              
==========================================
+ Hits       191219   191501     +282     
+ Misses      41884    41779     -105     
  Partials      765      765              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dsprenkels
Copy link
Collaborator Author

If we decide to go with single, I think we should rename DataFrame.item as well. Or this should be called item. Not sure yet.

@ritchie46 The inconvenient thing about .item() is that, at the moment, it does different things depending on the argument, which I'd propose renaming to get() and single().

IRAggExpr::Implode(node)
| IRAggExpr::First(node)
| IRAggExpr::Last(node)
| IRAggExpr::Single(node) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed optimization - Single doesn't observe ordering - it only observes length.

It should be in a separate branch that just returns O::None (i.e. no observable orderings, since we are returning a scalar in the Ok(_) case).

@mcrumiller
Copy link
Contributor

mcrumiller commented Oct 16, 2025

I am not a huge fan of single mainly because "single precision" is so commonly used.

I like into_value() or to_value(), both feel a little bit clearer. Not sure what others think of my ideas.

@cmdlineluser
Copy link
Contributor

#24475 suggested the name .one() after more_itertools.one()

@mcrumiller
Copy link
Contributor

#24475 suggested the name .one() after more_itertools.one()

The problem is that one() doesn't sound like it requires the sequence to already be a single value, just that you're only selecting one out, whereas to_value() implies that you can get a failure when you don't already have just a value.

@dsprenkels
Copy link
Collaborator Author

@MarcoGorelli It's more that there is a mismatch between DataFrame and Expr, where DataFrame.item() is used to index items, but for Expr it is Expr.get()

@dsprenkels dsprenkels added merge-after-dsl-unfreeze do not merge This pull requests should not be merged right now labels Oct 20, 2025
@dsprenkels dsprenkels marked this pull request as ready for review October 20, 2025 08:59
Copy link
Collaborator

@coastalwhite coastalwhite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, a few small changes.

@dsprenkels dsprenkels removed do not merge This pull requests should not be merged right now merge-after-dsl-unfreeze labels Oct 20, 2025
@dsprenkels dsprenkels merged commit 0528f53 into pola-rs:main Oct 20, 2025
29 checks passed
@dsprenkels dsprenkels deleted the issue-8689_single branch October 20, 2025 17:35
@ritchie46
Copy link
Member

ritchie46 commented Oct 21, 2025

Ai, this was merged a bit too early. :') Not a big deal, will work around it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or an improvement of an existing feature python Related to Python Polars rust Related to Rust Polars

Projects

None yet

8 participants