Skip to content

Close the feature gap between the Where-Object cmdlet and the .Where() array method, introduce -First, -Last, ... switches #13834

@mklement0

Description

@mklement0

Summary of the new feature/enhancement

Update for clarification: The gist of this proposal is to bring valuable filter functionality that currently only exists in the in-memory .Where() array method to its pipeline counterpart, Where-Object.
(Always using .Where() isn't an option with large input sets, because you'd have to collect all input in memory first.)

The .Where() array method, which is the in-memory equivalent of the pipeline-based Where-Object cmdlet, offers a number of additional features, such as the ability to optionally stop matching after the first match is found, which can be an important optimization technique, and the ability to output all objects that come before/after a matching one:

First / -First example:

# OK - very fast, because - despite the large input collection - processing stops after the first match.
(1..1e6).Where({ $_ -eq 10 }, 'First')  # -> 10

# WISHFUL THINKING: Add a -First switch (among several others - see below).
1..1e6 | Where-Object { $_ -eq 10 } -First

# Without it, ALL elements are processed - SLOW
1..1e6 | Where-Object { $_ -eq 10 }

# Current workaround is cumbersome.
1..1e6  | Where-Object { $_ -eq 10 } | Select-Object -First 1

SkipUntil / -SkipUntil example:

(1, 2, 42, 43).Where({ $_ -eq 42 }, 'SkipUntil') # -> 42, 43

# WISHFUL THINKING: Add a -SkipUntil switch.
1, 2, 42, 43 | Where-Object { $_ -eq 42 } -SkipUntil

Based on the current .Where() features, the following switches should be introduced with the same behavior, mirroring the WhereOperatorSelectionMode enumeration values:

-First, -Last, -SkipUntil, -Until, -Split

Note:

  • -Split partitions the input into two and returns two collections, so it would in effect require collecting all input in memory first before producing output, which would have to be clearly documented.

  • The .Where() method has an optional numeric parameter, numberToReturn, that modifies the operations, such as 2 with First returning the first two matches; since we don't have a syntax for switches with optional (non-Boolean) arguments for commands (see Feature Request: Variable Parameter with switch-like capability #12104), we have the following options:

    • Option A: Simply omit this aspect of the functionality and invariably default to 1, which is likely fine in the majority of cases; if a different number is needed, Select-Object -First/-Last $n can be piped to.

    • Option B: Implement -First and -Last not as _switches, but as -First and-Last ` ; the potential downside is that a number argument is then mandatory.

    • Option C: Given that numberToReturn also modifies all other functionality - though there's likely less of a need for that - implement a separate -Count <int> parameter, which in the absence of any of the switches would imply -First.

  • For these behaviors to be implemented efficiently, they have to stop the pipeline on demand, as Select-Object already does. However, the latter does so in a problematic fashion - not giving other cmdlets a chance to run their End blocks - which should be addressed (independently) as well: see Select-Object -First X skips End{ } blocks of previous cmdlets #7930

On a meta note: You can skip the obsolete comments that follow and resume reading at this comment.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Enhancementthe issue is more of a feature request than a bugResolution-No ActivityIssue has had no activity for 6 months or moreWG-Cmdlets-Corecmdlets in the Microsoft.PowerShell.Core module

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions