_.map
The one underscore node you'll actually want — map every element through a transform.
- list_or_dict
- iteratee
- LIST
If you only grab one node from the ovum/underscore family in sfinktah/comfy-ovum, make it _.map. It applies a transformation to every element of a list (or every value of a dict) and collects the results into a new list. This is the workhorse - the thing that turns a list of dicts into a list of names, or a list of numbers into a list of strings, without a pile of per-element plumbing.
What it is
A graph wrapper around map in underscore3, a Python port of Underscore.js. The iteratee - the function doing the transforming - is invoked with three arguments: the value, its index (or key), and the whole list. And critically, the iteratee is normalized through _.iteratee, which means you don't have to hand it a real function every time.
Inputs that matter
Three, and the first two are the ones you'll set:
list_or_dict(type*) - the collection to map over.iteratee(type*, force-input) - an ANY socket for the transformation. Accepts a function, a key string (plucks that field), or an object shorthand (matches properties).iteratee_json(STRING, multiline) - JSON or a key selector, used when theiterateesocket isn't connected. This is your durable, save-friendly path.
Output is properly typed LIST. Feed a _.CHAIN and you get a chain back for continued chaining, resolved with _.value.
The two ways to drive it
The key-selector shorthand is the everyday win. Feed it a list of dicts and set iteratee_json to "name", and you get a list of the name values. That's the "pluck" pattern, and it's the fastest way to extract a column out of structured data. For real logic, wire a function into the iteratee socket - the pack even ships _.iteratee to build one from shorthands, and the README mentions an experimental feature where you supply an iteratee node class and it builds a tiny per-item subgraph that runs and collects its output. That last part is genuinely experimental territory; treat it as a playground, not a pillar.
The save/reload caveat
Functions are live Python objects and don't survive a workflow save/reload as JSON. If your map depends on a function in the iteratee socket, reloading the workflow will leave it empty - rebuild it in the live session. The key-selector form (iteratee_json) survives fine because it's text. If you're building a workflow you'll share or reopen later, prefer the JSON/key path.
Installing comfy-ovum
ComfyUI Manager: search for comfy-ovum, install, restart. Or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/sfinktah/comfy-ovum
pip install -r comfy-ovum/requirements.txt
Restart and you're done. No model downloads, no CUDA - pure-Python utilities. The family is officially "work in progress," and _.map is where the polish shows most - but the key-selector path is solid enough to use for real work.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| list_or_dictopt | * | Primary input object (expected collection). You can still pass any JSON-serializable value. Also accepts _.CHAIN to continue chaining. | |
| iterateeopt | * | iteratee: ANY input to override widget. Accepts function, key string, or object shorthand. | |
| iteratee_jsonopt | STRING | iteratee_json: JSON or key selector. Used when 'iteratee' input is not connected. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| LIST | LIST | — |