Skip to content

indexing by a list of slices #10479

Open

Description

@keewis

Is your feature request related to a problem?

In some situations, it is important to be able to select multiple (disconnected) contiguous regions along a dimension, even if the dimension itself is very large.

If there's enough client memory, it is possible to emulate this by materializing the slices into an array of integers, but this becomes infeasible if that array is too large (and while supposedly we should be able to index by a dask integer array, I'm not sure how efficient that would be).

Examples of where this would be useful include:

  • The healpix MOC index at healpix moc index xarray-contrib/xdggs#151, where cell ids are represented as a set of disconnected ranges at the smallest possible refinement level. To be able to support Index.sel, I'd need to return a IndexSelResult with either a list of slices, or materialize these into an integer array and error out if that wouldn't fit into memory (or try to use dask as an indexer).
  • @tomwhite's use-case of selecting disconnected regions in a genome (see Add bcftools-style filtering sgkit-dev/sgkit#1330 (comment)). I'll let him provide further details.

cc @benbovy, @shoyer, @TomNicholas, @dcherian

Describe the solution you'd like

I'd love to be able to specify this as another kind of indexer:

indexer = SliceSet([slice(20, 5000), slice(12078432, 1850372894)])
ds.isel(cells=indexer)

but that will obviously further increase the complexity of the indexing machinery

Describe alternatives you've considered

Manually iterating of the slices, then concatenating the result is possible, but will have an additional overhead if done using the xarray API. However, I don't see a way that can work as part of IndexSelResult.

Activity

  1. benbovy commented on Jul 1, 2025

    @benbovy
    Member

    Manually iterating of the slices, then concatenating the result is possible

    Easiest I think would be to do that at the Variable level, i.e., implement a special case in Variable.isel() that will iterate over each slice and call Variable.concat() as needed. There may be some overhead but I think it would be limited at that level. If necessary it's still possible to introduce some internal fastpath in Variable.concat() or maintain an optimized internal version.

    For coordinate variables associated with a custom index, there's the possibility of implementing custom logic in Index.isel() (returning a new index object) and Index.create_variables() (create variables from the new index object) overridden methods. This will bypass Variable.isel() for those variables.

  2. shoyer commented on Jul 1, 2025

    @shoyer
    Member
  3. keewis commented on Jul 1, 2025

    @keewis
    CollaboratorAuthor

    Personally, my main motivation for this would be the return value of Index.sel, which we can't work around in user code.

    As for the lazy concatenation, I believe there's #10402 as an experiment on how this could be implemented.

  4. TomNicholas commented on Jul 1, 2025

    @TomNicholas
    Member

    I am curious if this has any crossover with what flox does to create groups

  5. ilan-gold commented on Jul 16, 2025

    @ilan-gold
    Contributor
  6. dcherian commented on Jul 16, 2025

    @dcherian
    Contributor

    technically we don't need lazy concat here. We can hack it using the fact that LazilyIndexedArray acts as a blocker on indexing; i.e. it only passes through indexers at compute time.

    So you could work with LazilyIndexedArray(MultiplySlicedArray(large_lazy_array)). This would only need concat at runtime.

  7. keewis commented on Jul 25, 2025

    @keewis
    CollaboratorAuthor

    that's a good point! This does work, but will need some thought on how to implement _updated_key (and _index_indexer_1d)

  8. dcherian commented on Jul 25, 2025

    @dcherian
    Contributor

    But doesn't that just condense all indexers down to a unified indexer that is then passed to LazilyIndexedArray.array?

  9. keewis commented on Jul 25, 2025

    @keewis
    CollaboratorAuthor

    yes, exactly. I'll have to think a bit more about whether implementing that is actually necessary, but it doesn't currently support lists of slices.

  10. dcherian commented on Jul 25, 2025

    @dcherian
    Contributor

    Yes I'm suggesting that you handle the list of slices elsewhere, wrap with LazilyIndexedArray and then assign to Variable

  11. keewis commented on Jul 25, 2025

    @keewis
    CollaboratorAuthor

    where would you create that class? In LazilyIndexedArray._oindex_get? That may result in something like LazilyIndexedArray(MultiplySlicedArray(LazilyIndexedArray(data))) if we're not careful, which would reduce the usefulness of _updated_key a bit.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions