clj 0.5.0
Utilities for lazy iterables
License: MIT
Requires Python: <4.0,>=3.9
Keywords: clj, clojure, lazy, iterables, generators

# clj

`clj` is a collection of functions to work with lazy iterators in Python.

It’s a module for those times when you did too much Clojure and came back to Python wondering where are all these
`distinct`, `drop-while`, `cycle`, `first`, etc.

The library is oriented toward laziness and performance. Functions are implemented with as little overhead as possible.

## Install

    pip install clj

Python requirement:
* 0.4.x: Python 3.9+
* 0.3.x: Python 3.7+
* 0.2.x: Python 3.7+
* 0.1.x: Python 2.7, 3.3+

## Usage

The library is considered stable and is used in production.

### Example

```clojure
;; Clojure
(->> coll (map inc) (filter even?) distinct count println)
; which expands to:
(println (count (distinct (filter even? (map inc coll)))))
```

```python
# Python
from clj import count, distinct, inc, is_even

print(count(distinct(filter(is_even, map(inc, coll)))))
```

Note that `count()` works on both sequences in generators; in the latter case it doesn’t load everything in memory like
e.g. `len(list(g))` would do.

## Core Ideas

* Lazy by default. All functions should work on arbitrary iterators and return generators.
* This is Python. We keep Python’s semantics instead of trying to reproduce Clojure in Python (e.g. `0` and `[]` are
  logically true in Clojure but false in Python; `None` is not equivalent to an empty collection).
* Don’t Reinvent the Wheel. We don’t reimplement built-in functions unless they miss something, like `range` that can’t
  be called without argument to yield an infinite sequence.

## Support

The general naming scheme is: use underscores instead of hyphens; start the function with `is_` if its Clojure
counterparts ends with a `?`.

### Sequences

We aim to implement all Clojure functions that operate on sequences
(see [the list here][seqs]). They all work on iterables and return generators by default (Python’s closest equivalent of
lazy seqs). We don’t support transducers.

[seqs]: http://clojure.org/reference/sequences

| Clojure           | `clj`           | Comment                                                                                                             |
|-------------------|:----------------|---------------------------------------------------------------------------------------------------------------------|
| `distinct`        | `distinct`      |                                                                                                                     |
| `filter`          | `filter`        | Alias to Python’s built-in `filter`.                                                                                |
| `remove`          | `remove`        |                                                                                                                     |
| `keep`            | `keep`          |                                                                                                                     |
| `keep-indexed`    | `keep_indexed`  |                                                                                                                     |
| `cons`            | `cons`          |                                                                                                                     |
| `concat`          | `concat`        | Equivalent to `itertools.chain`.                                                                                    |
| `lazy-cat`        | -               | Use Python’s `itertools.chain`.                                                                                     |
| `mapcat`          | `mapcat`        |                                                                                                                     |
| `cycle`           | `cycle`         |                                                                                                                     |
| `interleave`      | `interleave`    |                                                                                                                     |
| `interpose`       | `interpose`     |                                                                                                                     |
| `rest`            | `rest`          |                                                                                                                     |
| `next`            | -               | Use `rest`.                                                                                                         |
| `fnext`           | -               | Use `second`.                                                                                                       |
| `nnext`           | -               | Use `rest(rest(…))`                                                                                                 |
| `drop`            | `drop`          |                                                                                                                     |
| `drop-while`      | `drop_while`    | Equivalent to `itertools.dropwhile`.                                                                                |
| `nthnext`         | -               | Use `drop`.                                                                                                         |
| `take`            | `take`          |                                                                                                                     |
| `take-nth`        | `take_nth`      |                                                                                                                     |
| `take-while`      | `take_while`    | Equivalent to `itertools.takewhile`.                                                                                |
| `butlast`         | `butlast`       |                                                                                                                     |
| `drop-last`       | `drop_last`     |                                                                                                                     |
| `flatten`         | `flatten`       |                                                                                                                     |
| `reverse`         | `reverse`       |                                                                                                                     |
| `sort`            | -               | Use Python’s built-in `sort`.                                                                                       |
| `sort-by`         | -               | Use `sort(…, key=your_function)`.                                                                                   |
| `shuffle`         | `shuffle`       |                                                                                                                     |
| `split-at`        | `split_at`      |                                                                                                                     |
| `split-with`      | `split_with`    |                                                                                                                     |
| `partition`       | `partition`     | `(partition n step pad coll)` becomes `partition(coll, n, step, pad)`. Only the case `step=n` is supported for now. |
| `partition-all`   |                 |                                                                                                                     |
| `partition-by`    | `partition_by`  |                                                                                                                     |
| `map`             | `map`           | Alias to Python’s built-in `map`.                                                                                   |
| `pmap`            | -               |                                                                                                                     |
| `replace`         | `replace`       |                                                                                                                     |
| `reductions`      | `reductions`    | `(reductions f i c)` becomes `reductions(f, c, i)`.                                                                 |
| `map-indexed`     | `map_indexed`   |                                                                                                                     |
| `seque`           | -               |                                                                                                                     |
| `first`           | `first`         | `None` is not a valid parameter.                                                                                    |
| `ffirst`          | `ffirst`        | `None` is not a valid parameter.                                                                                    |
| `nfirst`          | `nfirst`        |                                                                                                                     |
| `second`          | `second`        |                                                                                                                     |
| `nth`             | `nth`           |                                                                                                                     |
| `last`            | `last`          |                                                                                                                     |
| `rand-nth`        | -               | Use Python’s `random.choice`.                                                                                       |
| `zipmap`          | `zipmap`        |                                                                                                                     |
| `into`            | -               |                                                                                                                     |
| `reduce`          | -               | Use Python’s `functools.reduce`.                                                                                    |
| `set`             | -               | Use Python’s `set`.                                                                                                 |
| `vec`             | -               | Use Python’s `list`.                                                                                                |
| `into-array`      | -               | Use Python’s `list`.                                                                                                |
| `to-array-2d`     | -               |                                                                                                                     |
| `frequencies`     | -               | Use Python’s `collections.Counter`.                                                                                 |
| `group-by`        | `group_by`      |                                                                                                                     |
| `apply`           | -               | Use the `f(*args)` construct.                                                                                       |
| `not-empty`       | -               |                                                                                                                     |
| `some`            | `some`          |                                                                                                                     |
| `seq?`            | `is_seq`        |                                                                                                                     |
| `every?`          | `every`         |                                                                                                                     |
| `not-every?`      | `not_every`     |                                                                                                                     |
| `not-any?`        | `not_any`       |                                                                                                                     |
| `empty?`          | -               |                                                                                                                     |
| `empty`           | `empty`         |                                                                                                                     |
| `doseq`           | -               | Use `for … in`.                                                                                                     |
| `dorun`           | `dorun`         |                                                                                                                     |
| `doall`           | -               | Use Python’s `list`.                                                                                                |
| `realized?`       | -               |                                                                                                                     |
| `seq`             | -               | Use Python’s `list`.                                                                                                |
| `vals`            | -               | Use Python’s `dict.values`.                                                                                         |
| `keys`            | -               | Use Python’s `dict.keys`.                                                                                           |
| `rseq`            | -               |                                                                                                                     |
| `subseq`          | -               |                                                                                                                     |
| `rsubseq`         | -               |                                                                                                                     |
| `repeatedly`      | `repeatedly`    |                                                                                                                     |
| `iterate`         | `iterate`       |                                                                                                                     |
| `repeat`          | `repeat`        | `(repeat n x)` becomes `repeat(x, n)`. Equivalent to `itertools.repeat`.                                            |
| `range`           | `range`         | Prefer Python’s `range` for everything but infinite generators.                                                     |
| `line-seq`        | -               | Loop over an `io.BufferedReader`.                                                                                   |
| `resultset-seq`   | -               |                                                                                                                     |
| `re-seq`          | -               | Use Python’s `re.finditer`.                                                                                         |
| `tree-seq`        | `tree_seq`      |                                                                                                                     |
| `file-seq`        | -               | Use Python’s `os.walk`.                                                                                             |
| `xml-seq`         | -               |                                                                                                                     |
| `iterator-seq`    | -               |                                                                                                                     |
| `enumeration-seq` | -               |                                                                                                                     |
| `hash-map`        | -               | Use Python’s `dict`.                                                                                                |
| `array-map`       | -               | Use Python’s `dict`.                                                                                                |
| `sorted-map`      | -               | Use `collections.OrderedDict`.                                                                                      |
| `sorted-map-by`   | -               |                                                                                                                     |
| `hash-set`        | -               | Use Python’s `set`.                                                                                                 |
| `set`             | -               | Use Python’s `set`.                                                                                                 |
| `sorted-set`      | -               |                                                                                                                     |
| `sorted-set-by`   | -               |                                                                                                                     |
| `dedupe`          | `dedupe`        |                                                                                                                     |

We also implemented `count`, which uses Python’s `len` when possible and fallbacks on a `for` loop for other cases.

### Functions

We also provide miscellaneous functions as well as functions that work on functions.

| Clojure           | `clj`           | Comment                          |
|-------------------|:----------------|----------------------------------|
| `identity`        | `identity`      |                                  |
| `partial`         | -               | Use Python’s `functools.partial` |
| `comp`            | `comp`          |                                  |
| `complement`      | `complement`    |                                  |
| `constantly`      | `constantly`    |                                  |
| `juxt`            | `juxt`          |                                  |
| `distinct?`       | `is_distinct`   |                                  |

| Clojure           | `clj`           | Comment                          |
|-------------------|:----------------|----------------------------------|
| `inc`             | `inc`           |                                  |
| `dec`             | `dec`           |                                  |