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.
pip install clj
;; Clojure
(println (count (distinct (filter even? (map inc coll)))))
# Python
from clj import count, distinct, filter, inc, map
even = lambda e: ~e&1
print(count(distinct(filter(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.
- 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:
range
because it can’t be called without argument to yield an infinite sequence;map
andfilter
in Python 2 because they aren’t lazy.
The general naming scheme is: use underscores instead of hyphens; start the
function with is_
if its Clojure counterparts ends with a ?
.
We aim to implement all Clojure functions that operate on sequences (see the list here). They all work on iterables and return generators by default (Python’s closest equivalent of lazy seqs). We don’t support transducers.
Clojure | clj |
Comment |
---|---|---|
distinct |
distinct |
|
filter |
filter |
|
remove |
remove |
|
keep |
keep |
|
keep-indexed |
keep_indexed |
|
cons |
cons |
|
concat |
concat |
Deprecated. Use Python’s 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 |
Deprecated. Use Python’s itertools.dropwhile |
nthnext |
- | Use drop . |
take |
take |
|
take-nth |
take_nth |
|
take-while |
take_while |
Deprecated. Use Python’s 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-all |
||
partition-by |
||
map |
map |
|
pmap |
- | |
replace |
replace |
|
reductions |
reductions |
(reductions f i c) becomes reductions(f, c, i) |
map-indexed |
map_indexed |
|
seque |
- | |
first |
first |
|
ffirst |
ffirst |
|
nfirst |
nfirst |
|
second |
second |
|
nth |
nth |
|
last |
last |
|
rand-nth |
- | Use Python’s random.choice . |
zipmap |
zipmap |
|
into |
- | |
reduce |
- | Use Python’s built-in 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 |
- | |
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) . |
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.
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 |