Metadata-Version: 2.4
Name: smartarr
Version: 0.1.3
Summary: Expressive array utilities with an optional C backend.
Author: OpenAI Codex
License-Expression: MIT
Keywords: array,utilities,c-extension,numpy
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: C
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: numpy
Requires-Dist: numpy>=1.24; extra == "numpy"
Dynamic: license-file

# smartarr

`smartarr` is an expressive array utility layer for Python with a clean `smart(arr)` API and an optional C backend for fast core operations.

## Why it exists

The goal is simple:

- one readable interface for lists, tuples, and NumPy arrays
- fast common operations when the C extension is available
- chainable transformations that still feel like Python

```python
from smartarr import smart

value = smart([1, 2, 3, 4, 5]).rotate(2).reverse().middle()
print(value)  # 1
```

## Install

Local install from this project:

```bash
python -m pip install .
```

Editable install for development:

```bash
python -m pip install -e .
```

Optional NumPy support:

```bash
python -m pip install ".[numpy]"
```

If a compiler is available, `smartarr` builds its C extension automatically. If not, installation still succeeds and falls back to the pure Python backend.

## Quick start

```python
from smartarr import smart

arr = smart([1, 2, 3, 4])

print(arr.first())                 # 1
print(arr.last())                  # 4
print(arr.middle())                # 3
print(arr.middle(mode="left"))     # 2
print(arr.middle(mode="avg"))      # 2.5
print(arr.size())                  # 4
print(len(arr))                    # 4
print(arr.rotate(1).to_list())     # [4, 1, 2, 3]
print(arr.reverse().to_list())     # [4, 3, 2, 1]
print(arr.chunk(2).to_list())      # [[1, 2], [3, 4]]
print(arr.window(2).to_list())     # [[1, 2], [2, 3], [3, 4]]
print(arr.peaks().to_list())       # local maxima values
print(arr.peaks(mode="index").to_list())  # local maxima indexes
print(arr.duplicates().to_list())  # unique duplicated values
print(arr.duplicates(mode="all").to_list())  # every repeated occurrence after the first
```

## Design notes

- `middle()` defaults to the right-middle element for even-length arrays, matching `arr[len(arr) // 2]`.
- `SmartArray` operations are non-mutating by default. Methods like `rotate()` and `reverse()` return a new wrapper and leave the original array unchanged.
- Prefer `len(arr)` or `arr.size()` for length checks. `arr.len()` remains as a compatibility alias.
- Structural methods return a new `SmartArray`, so chaining works naturally.
- Terminal methods return a final value, such as an element, a number, or a dictionary.
- Flat transformations preserve the original adapter where practical. Shape-changing operations return list-shaped data by default.
- `random()` returns one element when `n` is omitted, samples without replacement when `replace=False`, and samples with replacement when `replace=True`. A `seed` makes output deterministic.
- `peaks()` returns local maxima values by default. Use `mode="index"` to return their positions.
- `duplicates()` returns each duplicated value once by default. Use `mode="all"` to return every repeated occurrence after the first.
- `flatten()` performs a deep recursive flatten across nested iterables, except string-like values such as `str`, `bytes`, and `bytearray`.
- `flatten()` follows the iteration order of the source containers. Ordered iterables stay ordered; unordered iterables such as `set` keep their native iteration behavior.
- `reshape()` validates that the requested shape exactly matches the flattened element count.
- `window()` returns an empty result when the requested window size is larger than the array length.
- `reduce()` requires either a non-empty array or an explicit `initial` value.
- `frequency()` returns counts in first-seen insertion order on Python 3.7+.

## Performance Notes

- The current C backend accelerates core access and array operations such as `first`, `last`, `middle`, `rotate`, `reverse`, `find`, `count`, `contains`, `chunk`, `window`, and `is_sorted`.
- Higher-level methods such as `map`, `filter`, `reduce`, `sum`, `mean`, `median`, `peaks`, `unique`, `duplicates`, `frequency`, `flatten`, and `reshape` currently run in Python.
- This means the API is already hybrid, but the biggest performance wins will come from moving heavier algorithms into the C layer over time.

## Supported input types

- `list`
- `tuple`
- NumPy `ndarray` when NumPy is installed
- general iterables such as `range`

## Current feature coverage

### V1

- `first`
- `last`
- `middle`
- `rotate`
- `reverse`
- `len`
- `is_empty`

### V2

- `chunk`
- `window`
- `random`
- `find`
- `count`
- `contains`
- `is_sorted`
- `sorted`

### V3

- `map`
- `filter`
- `reduce`
- `sum`
- `mean`
- `median`
- `min`
- `max`
- `peaks`
- `unique`
- `duplicates`
- `frequency`
- `flatten`
- `reshape`

## Development

Run tests:

```bash
python -m unittest discover -s tests -v
```

## License

MIT
