{"id":2615,"library":"ndindex","title":"Ndindex","description":"ndindex is a Python library designed for representing and manipulating objects that can serve as valid indices for NumPy arrays, including slices, integers, ellipses, None, and integer/boolean arrays, and tuples containing these types. It provides a uniform API for these objects, ensuring correct semantics aligned with NumPy's `ndarray` indexing rules. The current version is 1.10.1, and it maintains an active release cadence with recent updates.","status":"active","version":"1.10.1","language":"en","source_language":"en","source_url":"https://github.com/Quansight-Labs/ndindex","tags":["numpy","indexing","array","slice","utility"],"install":[{"cmd":"pip install ndindex","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core functionality relies on concepts and types from NumPy for array indexing.","package":"numpy","optional":false}],"imports":[{"note":"The primary API entry point is the `ndindex()` function, usually imported directly to convert Python index objects to ndindex objects. Direct `import ndindex` requires prefixing all calls, which is less common for this library's typical usage.","wrong":"import ndindex","symbol":"ndindex","correct":"from ndindex import ndindex"},{"note":"Classes like `Slice`, `Integer`, `Tuple` are typically imported directly for convenience, or accessed via `ndindex.Slice` if `ndindex` is imported as a module.","wrong":"import ndindex.Slice","symbol":"Slice","correct":"from ndindex import Slice"}],"quickstart":{"code":"import numpy as np\nfrom ndindex import ndindex, Slice, Tuple\n\n# Create an ndindex object from a Python slice\nidx_slice = ndindex(slice(1, 10, 2))\nprint(f\"Ndindex from slice: {idx_slice}\")\n\n# Canonicalize a slice (reduce to simplest form)\ncanonical_slice = Slice(None, 10).reduce()\nprint(f\"Canonical slice: {canonical_slice}\")\n\n# Canonicalize for a specific array shape\nshaped_slice = Slice(-5, 10, 2).reduce(12)\nprint(f\"Slice reduced for shape 12: {shaped_slice}\")\n\n# Manipulate a tuple index\ntuple_idx = Tuple(0, slice(0, 5), None, 1)\nprint(f\"Tuple index: {tuple_idx}\")\n\n# Get the raw Python index to use with NumPy\nnp_array = np.arange(20).reshape(2, 10)\nraw_index = tuple_idx.raw\nprint(f\"Raw Python index: {raw_index}\")\n\n# Use the raw index with a NumPy array\ntry:\n    indexed_array = np.arange(100).reshape(10, 10)[raw_index] # Example with a 2D array\n    print(f\"Indexed array shape: {indexed_array.shape}\")\nexcept IndexError as e:\n    print(f\"Indexing with {raw_index} failed due to: {e}\")","lang":"python","description":"This quickstart demonstrates creating `ndindex` objects from basic Python indices, canonicalizing slices (both generally and for a specific array shape), and converting an `ndindex` object back into a raw Python index suitable for use with NumPy arrays. It highlights the `reduce()` method for canonicalization and `raw` attribute for NumPy compatibility."},"warnings":[{"fix":"Always use `try-except IndexError` blocks when applying `idx.raw` to a NumPy array if out-of-bounds indexing is a possibility. Perform explicit bounds checking if needed before constructing the `ndindex` object if strict validation is required.","message":"ndindex objects assume that indexing will not raise an `IndexError`. Operations like `reduce()` and transformations do not validate against array bounds; they assume the index is valid for *some* array. Users must handle `IndexError` when applying `ndindex.raw` to an actual NumPy array. [1, 4, 6, 8]","severity":"gotcha","affected_versions":"All versions"},{"fix":"To canonicalize an index or reduce it to its simplest equivalent form, you must explicitly call the `.reduce()` method on the `ndindex` object (e.g., `Slice(None, 10).reduce()`). If comparing two indices for equivalence over a specific array shape, use `idx1.reduce(shape) == idx2.reduce(shape)` rather than `idx1 == idx2`. [1, 4]","message":"By default, `ndindex` class constructors (e.g., `Slice(None, 10)`) only perform basic type checking and do not canonicalize the index. This means `Slice(None, 10)` is not strictly equal to `Slice(0, 10, 1)` by default. [1, 4, 8]","severity":"gotcha","affected_versions":"All versions"},{"fix":"To check if two `ndindex` objects are equivalent in terms of the elements they would select from an array, first call their `.reduce()` method, optionally with an array `shape` argument if the context is known. Then compare the reduced objects: `idx1.reduce(shape) == idx2.reduce(shape)`. [1]","message":"Direct `==` comparison between `ndindex` objects performs exact equality checking, which might not reflect if two indices actually refer to the same elements in an array. For instance, `Slice(0, 10)` and `Slice(None, 10)` are not equal with `==`. [1]","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-10T00:00:00.000Z","next_check":"2026-07-09T00:00:00.000Z"}