Collection operations for PTC-Lisp runtime.
Provides filtering, mapping, sorting, and other collection manipulation functions.
Selection operations (filter, remove, find, some, every?, not_any?,
take_while, drop_while) are implemented in Collection.Select.
Transformation operations (map, mapv, mapcat, keep, map_indexed)
are implemented in Collection.Transform.
Summary
Functions
Generate all n-combinations from a collection.
Returns a new seq with item prepended.
Returns an empty collection of the same type, or nil for nil input.
Like filter but always returns a vector. In PTC-Lisp, this is equivalent to filter since all sequences are vectors.
Variadic interleave over seqables (Clojure's 0/1/n arity).
Returns a list with sep inserted between each element.
Variadic version of max-by that supports both (max-by key coll) and (apply max-by key item1 item2 ...).
Returns the x for which (f x) is greatest. Matches Clojure's max-key.
Variadic version of min-by that supports both (min-by key coll) and (apply min-by key item1 item2 ...).
Returns the x for which (f x) is least. Matches Clojure's min-key.
Returns the last element of a vector without removing it. Returns nil for nil or empty collections.
Returns the collection without the last element. Returns nil for nil. Returns nil for empty collections.
Transform a tree bottom-up by applying f to each node after recursing into children.
Transform a tree top-down by applying f to each node before recursing into children.
Clojure's clojure.core/replace seq form: replace each element of coll
with its lookup in smap (a map or an indexable vector), leaving elements
absent from smap unchanged.
Returns a subvector from start (inclusive) to end (exclusive). Clamps indices to valid range.
Returns a depth-first lazy sequence of all nodes in a tree.
Generic tree walker. Applies inner to each element of form, then applies outer to the result.
Functions
Generate all n-combinations from a collection.
Works with any seqable: lists, strings, maps.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.combinations([1, 2, 3, 4], 3)
[[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
iex> PtcRunner.Lisp.Runtime.Collection.combinations([1, 2], 0)
[[]]
iex> PtcRunner.Lisp.Runtime.Collection.combinations([1, 2], 3)
[]
Returns a new seq with item prepended.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.cons(1, [2, 3])
[1, 2, 3]
iex> PtcRunner.Lisp.Runtime.Collection.cons(1, nil)
[1]
Returns an empty collection of the same type, or nil for nil input.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.empty([1, 2, 3])
[]
iex> PtcRunner.Lisp.Runtime.Collection.empty(%{a: 1})
%{}
Like filter but always returns a vector. In PTC-Lisp, this is equivalent to filter since all sequences are vectors.
Variadic interleave over seqables (Clojure's 0/1/n arity).
Each argument is coerced through interleave_seq/1: lists pass through,
strings become their graphemes (GAP-S98), and nil becomes [] (GAP-S20) —
matching the interpose sibling and Clojure. Direct maps/sets have no clause
and raise, surfaced as a type_error (DIV-29: positional ops require an
explicit ordered view via seq/entries/keys/vals).
Zero args yield []; a single seqable is returned as its own seq; multiple
seqables are interleaved, stopping at the shortest.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.interleave_variadic([])
[]
iex> PtcRunner.Lisp.Runtime.Collection.interleave_variadic([[1, 2]])
[1, 2]
iex> PtcRunner.Lisp.Runtime.Collection.interleave_variadic([[1, 2], [3, 4], [5, 6]])
[1, 3, 5, 2, 4, 6]
iex> PtcRunner.Lisp.Runtime.Collection.interleave_variadic(["ab", [1, 2]])
["a", 1, "b", 2]
iex> PtcRunner.Lisp.Runtime.Collection.interleave_variadic([nil, [1]])
[]
Returns a list with sep inserted between each element.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.interpose(", ", ["a", "b", "c"])
["a", ", ", "b", ", ", "c"]
iex> PtcRunner.Lisp.Runtime.Collection.interpose(:x, [1])
[1]
iex> PtcRunner.Lisp.Runtime.Collection.interpose(:x, [])
[]
iex> PtcRunner.Lisp.Runtime.Collection.interpose(:x, nil)
[]
iex> PtcRunner.Lisp.Runtime.Collection.interpose(nil, [1, 2, 3])
[1, nil, 2, nil, 3]
iex> PtcRunner.Lisp.Runtime.Collection.interpose(",", "ab")
["a", ",", "b"]
See PtcRunner.Lisp.Runtime.Collection.Transform.keep_indexed/2.
See PtcRunner.Lisp.Runtime.Collection.Transform.map_indexed/2.
Variadic version of max-by that supports both (max-by key coll) and (apply max-by key item1 item2 ...).
Returns the x for which (f x) is greatest. Matches Clojure's max-key.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.max_key_variadic([&String.length/1, "a", "abc", "ab"])
"abc"
Variadic version of min-by that supports both (min-by key coll) and (apply min-by key item1 item2 ...).
Returns the x for which (f x) is least. Matches Clojure's min-key.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.min_key_variadic([&String.length/1, "a", "abc", "ab"])
"a"
Returns the last element of a vector without removing it. Returns nil for nil or empty collections.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.peek([1, 2, 3])
3
iex> PtcRunner.Lisp.Runtime.Collection.peek([])
nil
Returns the collection without the last element. Returns nil for nil. Returns nil for empty collections.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.pop([1, 2, 3])
[1, 2]
iex> PtcRunner.Lisp.Runtime.Collection.pop([])
nil
Transform a tree bottom-up by applying f to each node after recursing into children.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.postwalk(&Function.identity/1, [1, [2, 3]])
[1, [2, 3]]
Transform a tree top-down by applying f to each node before recursing into children.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.prewalk(&Function.identity/1, [1, [2, 3]])
[1, [2, 3]]
Clojure's clojure.core/replace seq form: replace each element of coll
with its lookup in smap (a map or an indexable vector), leaving elements
absent from smap unchanged.
coll is normalized as a seq, so any seqable (list, vector, string, map,
set, or nil) is accepted and an empty/nil input yields []. Flexible
lookup is used so PTC's keyword/string key normalization matches keyword
elements, and a vector smap resolves elements as 0-based indexes.
Lookup follows PTC's get value model: a list-valued element is treated as a
get-in path, not an exact key, so vector map keys are not matched (consistent
with (get {[:a] :x} [:a]) => nil) — a deliberate divergence from Clojure's
exact map-entry lookup.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.replace_coll(%{"a" => :x}, [:a, :b])
[:x, :b]
iex> PtcRunner.Lisp.Runtime.Collection.replace_coll([10, 20, 30], [0, 1, 2, 0])
[10, 20, 30, 10]
iex> PtcRunner.Lisp.Runtime.Collection.replace_coll([10, 20, 30], [5])
[5]
iex> PtcRunner.Lisp.Runtime.Collection.replace_coll(%{}, nil)
[]
Returns a subvector from start (inclusive) to end (exclusive). Clamps indices to valid range.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.subvec([0, 1, 2, 3, 4], 1, 3)
[1, 2]
iex> PtcRunner.Lisp.Runtime.Collection.subvec([0, 1, 2, 3, 4], 2)
[2, 3, 4]
Returns a depth-first lazy sequence of all nodes in a tree.
branch? is a predicate that returns true if a node has children. children returns the children of a branch node.
When branch? or children is a keyword, it is used to access that key from maps. For branch?, the result is checked for truthiness.
Examples
iex> tree = %{id: 1, children: [%{id: 2, children: []}, %{id: 3, children: []}]}
iex> result = PtcRunner.Lisp.Runtime.Collection.tree_seq(
...> fn node -> is_map(node) && Map.has_key?(node, :children) end,
...> fn node -> Map.get(node, :children, []) end,
...> tree
...> )
iex> Enum.map(result, & &1.id)
[1, 2, 3]
Generic tree walker. Applies inner to each element of form, then applies outer to the result.
For lists, walks each element. For maps, walks each [key, value] pair. For sets, walks each element and reconstructs the set. For scalars, just applies outer.
Examples
iex> PtcRunner.Lisp.Runtime.Collection.walk(&Function.identity/1, &Function.identity/1, [1, 2, 3])
[1, 2, 3]
iex> PtcRunner.Lisp.Runtime.Collection.walk(&Function.identity/1, &Enum.sum/1, [1, 2, 3])
6