Liking cljdoc? Tell your friends :D

co.multiply.pathling

Path finding and updating for nested data structures.

Path finding and updating for nested data structures.
raw docstring

find-whenclj/s

(find-when data pred)
(find-when data pred xf-or-opts)

Find all values in nested data structure matching predicate.

Returns vector of matching values in depth-first order, or nil if no matches.

The third parameter can be either:

  • A transducer to apply to matches (e.g., (map inc), (take 5), (filter pos?))
  • An options map with keys:
    • :xf - Transducer to apply to matches
    • :include-keys - When true, also match and collect map keys (default: false)

Supports early termination with transducers like (take n). Traversal order and key handling are the same as path-when. Transducers must complete to a collection or nil. Completion results are returned as a vector, or nil when empty; scalar completion results are errors.

Examples:

(find-when [1 {:a 2} {:b #{3 {:c 4}}}] number?)
;=> [1 2 3 4]

(find-when [1 {:a 2} {:b #{3 {:c 4}}}] number? (map inc))
;=> [2 3 4 5]

(find-when [1 {:a 2} {:b #{3 {:c 4}}}] number? (take 2))
;=> [1 2]

(find-when {:foo :bar :baz :qux} keyword? {:include-keys true})
;=> [:bar :foo :qux :baz]  ; order varies
Find all values in nested data structure matching predicate.

Returns vector of matching values in depth-first order, or `nil` if no matches.

The third parameter can be either:

- A transducer to apply to matches (e.g., `(map inc)`, `(take 5)`, `(filter pos?)`)
- An options map with keys:
  - `:xf` - Transducer to apply to matches
  - `:include-keys` - When true, also match and collect map keys (default: false)

Supports early termination with transducers like `(take n)`.
Traversal order and key handling are the same as `path-when`.
Transducers must complete to a collection or `nil`. Completion results are
returned as a vector, or `nil` when empty; scalar completion results are errors.

Examples:

```clojure
(find-when [1 {:a 2} {:b #{3 {:c 4}}}] number?)
;=> [1 2 3 4]

(find-when [1 {:a 2} {:b #{3 {:c 4}}}] number? (map inc))
;=> [2 3 4 5]

(find-when [1 {:a 2} {:b #{3 {:c 4}}}] number? (take 2))
;=> [1 2]

(find-when {:foo :bar :baz :qux} keyword? {:include-keys true})
;=> [:bar :foo :qux :baz]  ; order varies
```
sourceraw docstring

path-whenclj/s

(path-when data pred)
(path-when data pred opts)

Find all values in nested data structure matching predicate.

Returns map with:

  • :matches - Vector of matching values in depth-first order (or ArrayList if :raw-matches true)
  • :nav - Opaque navigation value for updating matches (use with update-paths)

Returns nil if no matches found.

Traversal is depth-first, children before their collection. With key matching, visit an entry's value subtree before its key; the key is tested as a whole, not recursively scanned. Map/set order follows the input collection and is not guaranteed to be the same across runtimes or collection implementations. Predicates inspect original values, including original collections.

Retain nav and pass it unchanged to update-paths with the scanned input. Do not depend on its concrete type, fields, or representation. Java internals are not part of the supported public API.

Options:

  • :include-keys - When true, also match map keys (default: false)
  • :raw-matches - When true, return a mutable ArrayList (JS array on ClojureScript). Mutate it in-place with replacement values, then pass it directly to update-paths to avoid copying the replacement collection. Updating persistent collections still allocates.

Examples:

(path-when [1 {:a 2} {:b #{3 {:c 4}}}] number?)
;=> {:matches [1 2 3 4], :nav ...}

(path-when [:a :b :c] number?)
;=> nil

;; Reuse the match accumulator
(let [{:keys [matches nav]} (path-when data task? {:raw-matches true})]
  (dotimes [i (.size matches)]
    (.set matches i (process (.get matches i))))
  (update-paths data nav matches))
Find all values in nested data structure matching predicate.

Returns map with:

- `:matches` - Vector of matching values in depth-first order (or ArrayList if `:raw-matches true`)
- `:nav` - Opaque navigation value for updating matches (use with `update-paths`)

Returns `nil` if no matches found.

Traversal is depth-first, children before their collection. With key matching,
visit an entry's value subtree before its key; the key is tested as a whole,
not recursively scanned. Map/set order follows the input collection and is
not guaranteed to be the same across runtimes or collection implementations.
Predicates inspect original values, including original collections.

Retain `nav` and pass it unchanged to `update-paths` with the scanned input.
Do not depend on its concrete type, fields, or representation. Java internals
are not part of the supported public API.

Options:

- `:include-keys` - When true, also match map keys (default: false)
- `:raw-matches` - When true, return a mutable ArrayList (JS array on ClojureScript).
                   Mutate it in-place with replacement values, then pass it directly
                   to `update-paths` to avoid copying the replacement collection.
                   Updating persistent collections still allocates.

Examples:

```clojure
(path-when [1 {:a 2} {:b #{3 {:c 4}}}] number?)
;=> {:matches [1 2 3 4], :nav ...}

(path-when [:a :b :c] number?)
;=> nil

;; Reuse the match accumulator
(let [{:keys [matches nav]} (path-when data task? {:raw-matches true})]
  (dotimes [i (.size matches)]
    (.set matches i (process (.get matches i))))
  (update-paths data nav matches))
```
sourceraw docstring

REMOVEclj/s

Sentinel value that signals removal of an element from its parent collection. Return this from an update-paths transform function to remove the element.

Behavior by collection type:

  • Maps: the key-value pair is removed (dissoc)
  • Sets: the element is not added to the result
  • Vectors/Lists: the element is removed and indices collapse

Removing a struct-map base entry converts that struct to an ordinary map. If the root itself is removed, the result is REMOVE (there is no parent). Use this opaque value directly; it has no keyword or serialized representation. It is reserved for replacement results. Storing it as ordinary input data is unsupported; no validation is performed for that case.

Example:

(transform-when data number? #(if (neg? %) REMOVE (inc %)))
;; Removes negative numbers, increments positive ones
Sentinel value that signals removal of an element from its parent collection.
Return this from an `update-paths` transform function to remove the element.

Behavior by collection type:

- Maps: the key-value pair is removed (`dissoc`)
- Sets: the element is not added to the result
- Vectors/Lists: the element is removed and indices collapse

Removing a struct-map base entry converts that struct to an ordinary map.
If the root itself is removed, the result is `REMOVE` (there is no parent).
Use this opaque value directly; it has no keyword or serialized representation.
It is reserved for replacement results. Storing it as ordinary input data is
unsupported; no validation is performed for that case.

Example:

```clojure
(transform-when data number? #(if (neg? %) REMOVE (inc %)))
;; Removes negative numbers, increments positive ones
```
sourceraw docstring

transform-whenclj/s

(transform-when data pred tf)
(transform-when data pred tf opts)

Transform all instances of items matching pred.

Predicates see the original structure. Transform functions run children before parents and receive collections with child updates already applied.

If tf returns REMOVE, the element is removed from its parent collection. Returns data unchanged if no matches found. Reconstruction, key collisions and root removal follow update-paths.

Options:

  • :include-keys - When true, also transform map keys that match pred (default: false)

Examples:

(transform-when data number? inc)
(transform-when data map? #(assoc % :processed true))
(transform-when {:a 1 :b 2} keyword? name {:include-keys true})
;=> {"a" 1, "b" 2}
(transform-when [1 -2 3 -4] number? #(if (neg? %) REMOVE (inc %)))
;=> [2 4]
Transform all instances of items matching `pred`.

Predicates see the original structure. Transform functions run children before
parents and receive collections with child updates already applied.

If `tf` returns `REMOVE`, the element is removed from its parent collection.
Returns data unchanged if no matches found.
Reconstruction, key collisions and root removal follow `update-paths`.

Options:

- `:include-keys` - When true, also transform map keys that match `pred` (default: false)

Examples:

```clojure
(transform-when data number? inc)
(transform-when data map? #(assoc % :processed true))
(transform-when {:a 1 :b 2} keyword? name {:include-keys true})
;=> {"a" 1, "b" 2}
(transform-when [1 -2 3 -4] number? #(if (neg? %) REMOVE (inc %)))
;=> [2 4]
```
sourceraw docstring

update-pathsclj/s

(update-paths data nav f-or-replacements)

Apply replacements to all locations identified in nav within data structure. Updates are applied depth-first (children before parents). A function receives the matched value with any child updates already applied. With key matching, an entry's value subtree is updated before its key.

Treat nav as opaque: obtain it from path-when and pass it unchanged with the scanned input. Its concrete type and internal representation are not API. Rescan after changing the navigated structure.

The third argument can be either:

  • A function: called with each matched value, returns the replacement
  • A collection (ArrayList/JS array, or vector): values are used sequentially by position

The collection-based form enables efficient bulk updates where replacements are computed externally and must be applied in traversal order. This is useful when the same accumulator returned by path-when with :raw-matches true has been mutated in-place with replacement values. Supply one replacement per match, in the order returned by path-when. Missing replacements throw when consumed; trailing replacements are ignored. A nil navigation returns the original data without consuming replacements. Do not mutate the replacement collection concurrently with the update.

If the replacement is REMOVE, the element is removed from its parent collection:

  • Maps: key-value pair is dissoc'd
  • Sets: element is not added to result
  • Vectors/Lists: element is removed and indices collapse

Struct maps retain their type unless a base key is renamed or removed, in which case the affected struct becomes an ordinary map. Extension entries can change without conversion. Records retain their type for value-only updates; removing a record field or transforming record keys can produce an ordinary map. Updated sequences are reconstructed as lists. Metadata and sorted comparators are preserved on reconstructed collections; a final parent replacement is returned as supplied, with its own metadata.

Key collisions use the last surviving updated entry in traversal order; updated entries can overwrite untouched entries. Sets collapse equal results. Removing the root returns REMOVE.

Example with function:

(let [{:keys [nav]} (path-when data number?)]
  (update-paths data nav inc))

Example reusing the match accumulator:

(let [{:keys [matches nav]} (path-when data task? {:raw-matches true})]
  ;; mutate matches in-place with results
  (dotimes [i (acc-size matches)]
    (acc-set! matches i (process (acc-get matches i))))
  (update-paths data nav matches))
Apply replacements to all locations identified in `nav` within data structure.
Updates are applied depth-first (children before parents).
A function receives the matched value with any child updates already applied.
With key matching, an entry's value subtree is updated before its key.

Treat `nav` as opaque: obtain it from `path-when` and pass it unchanged with
the scanned input. Its concrete type and internal representation are not API.
Rescan after changing the navigated structure.

The third argument can be either:

- A function: called with each matched value, returns the replacement
- A collection (ArrayList/JS array, or vector): values are used sequentially by position

The collection-based form enables efficient bulk updates where replacements are
computed externally and must be applied in traversal order. This is useful
when the same accumulator returned by `path-when` with `:raw-matches true`
has been mutated in-place with replacement values.
Supply one replacement per match, in the order returned by `path-when`.
Missing replacements throw when consumed; trailing replacements are ignored.
A nil navigation returns the original data without consuming replacements.
Do not mutate the replacement collection concurrently with the update.

If the replacement is `REMOVE`, the element is removed from its parent collection:

- Maps: key-value pair is dissoc'd
- Sets: element is not added to result
- Vectors/Lists: element is removed and indices collapse

Struct maps retain their type unless a base key is renamed or removed, in
which case the affected struct becomes an ordinary map. Extension entries can
change without conversion. Records retain their type for value-only updates;
removing a record field or transforming record keys can produce an ordinary map.
Updated sequences are reconstructed as lists. Metadata and sorted comparators
are preserved on reconstructed collections; a final parent replacement is
returned as supplied, with its own metadata.

Key collisions use the last surviving updated entry in traversal order;
updated entries can overwrite untouched entries. Sets collapse equal results.
Removing the root returns `REMOVE`.

Example with function:

```clojure
(let [{:keys [nav]} (path-when data number?)]
  (update-paths data nav inc))
```

Example reusing the match accumulator:

```clojure
(let [{:keys [matches nav]} (path-when data task? {:raw-matches true})]
  ;; mutate matches in-place with results
  (dotimes [i (acc-size matches)]
    (acc-set! matches i (process (acc-get matches i))))
  (update-paths data nav matches))
```
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close